/src/library/scala/collection/immutable/List.scala
Scala | 659 lines | 460 code | 63 blank | 136 comment | 112 complexity | 703115e039c8b3f4e6249a45129616f4 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, MIT
- /*
- * Scala (https://www.scala-lang.org)
- *
- * Copyright EPFL and Lightbend, Inc.
- *
- * Licensed under Apache License 2.0
- * (http://www.apache.org/licenses/LICENSE-2.0).
- *
- * See the NOTICE file distributed with this work for
- * additional information regarding copyright ownership.
- */
- package scala
- package collection
- package immutable
- import scala.annotation.unchecked.uncheckedVariance
- import scala.annotation.tailrec
- import mutable.{Builder, ListBuffer}
- import scala.collection.generic.DefaultSerializable
- import scala.runtime.Statics.releaseFence
- /** A class for immutable linked lists representing ordered collections
- * of elements of type `A`.
- *
- * This class comes with two implementing case classes `scala.Nil`
- * and `scala.::` that implement the abstract members `isEmpty`,
- * `head` and `tail`.
- *
- * This class is optimal for last-in-first-out (LIFO), stack-like access patterns. If you need another access
- * pattern, for example, random access or FIFO, consider using a collection more suited to this than `List`.
- *
- * ==Performance==
- * '''Time:''' `List` has `O(1)` prepend and head/tail access. Most other operations are `O(n)` on the number of elements in the list.
- * This includes the index-based lookup of elements, `length`, `append` and `reverse`.
- *
- * '''Space:''' `List` implements '''structural sharing''' of the tail list. This means that many operations are either
- * zero- or constant-memory cost.
- * {{{
- * val mainList = List(3, 2, 1)
- * val with4 = 4 :: mainList // re-uses mainList, costs one :: instance
- * val with42 = 42 :: mainList // also re-uses mainList, cost one :: instance
- * val shorter = mainList.tail // costs nothing as it uses the same 2::1::Nil instances as mainList
- * }}}
- *
- * @example {{{
- * // Make a list via the companion object factory
- * val days = List("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
- *
- * // Make a list element-by-element
- * val when = "AM" :: "PM" :: Nil
- *
- * // Pattern match
- * days match {
- * case firstDay :: otherDays =>
- * println("The first day of the week is: " + firstDay)
- * case Nil =>
- * println("There don't seem to be any week days.")
- * }
- * }}}
- *
- * @note The functional list is characterized by persistence and structural sharing, thus offering considerable
- * performance and space consumption benefits in some scenarios if used correctly.
- * However, note that objects having multiple references into the same functional list (that is,
- * objects that rely on structural sharing), will be serialized and deserialized with multiple lists, one for
- * each reference to it. I.e. structural sharing is lost after serialization/deserialization.
- *
- * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists "Scala's Collection Library overview"]]
- * section on `Lists` for more information.
- *
- * @define coll list
- * @define Coll `List`
- * @define orderDependent
- * @define orderDependentFold
- * @define mayNotTerminateInf
- * @define willNotTerminateInf
- */
- @SerialVersionUID(3L)
- sealed abstract class List[+A]
- extends AbstractSeq[A]
- with LinearSeq[A]
- with LinearSeqOps[A, List, List[A]]
- with StrictOptimizedLinearSeqOps[A, List, List[A]]
- with StrictOptimizedSeqOps[A, List, List[A]]
- with IterableFactoryDefaults[A, List]
- with DefaultSerializable {
- override def iterableFactory: SeqFactory[List] = List
- /** Adds an element at the beginning of this list.
- * @param elem the element to prepend.
- * @return a list which contains `x` as first element and
- * which continues with this list.
- * Example:
- * {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
- */
- def :: [B >: A](elem: B): List[B] = new ::(elem, this)
- /** Adds the elements of a given list in front of this list.
- *
- * Example:
- * {{{List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)}}}
- *
- * @param prefix The list elements to prepend.
- * @return a list resulting from the concatenation of the given
- * list `prefix` and this list.
- */
- def ::: [B >: A](prefix: List[B]): List[B] =
- if (isEmpty) prefix
- else if (prefix.isEmpty) this
- else {
- val result = new ::[B](prefix.head, this)
- var curr = result
- var that = prefix.tail
- while (!that.isEmpty) {
- val temp = new ::[B](that.head, this)
- curr.next = temp
- curr = temp
- that = that.tail
- }
- releaseFence()
- result
- }
- /** Adds the elements of a given list in reverse order in front of this list.
- * `xs reverse_::: ys` is equivalent to
- * `xs.reverse ::: ys` but is more efficient.
- *
- * @param prefix the prefix to reverse and then prepend
- * @return the concatenation of the reversed prefix and the current list.
- */
- def reverse_:::[B >: A](prefix: List[B]): List[B] = {
- var these: List[B] = this
- var pres = prefix
- while (!pres.isEmpty) {
- these = pres.head :: these
- pres = pres.tail
- }
- these
- }
- override final def isEmpty: Boolean = this eq Nil
- override def prepended[B >: A](elem: B): List[B] = elem :: this
- override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): List[B] = prefix match {
- case xs: List[B] => xs ::: this
- case _ if prefix.knownSize == 0 => this
- case b: ListBuffer[B] if this.isEmpty => b.toList
- case _ =>
- val iter = prefix.iterator
- if (iter.hasNext) {
- val result = new ::[B](iter.next(), this)
- var curr = result
- while (iter.hasNext) {
- val temp = new ::[B](iter.next(), this)
- curr.next = temp
- curr = temp
- }
- releaseFence()
- result
- } else {
- this
- }
- }
- // When calling appendAll with another list `suffix`, avoid copying `suffix`
- override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): List[B] = suffix match {
- case xs: List[B] => this ::: xs
- case _ => super.appendedAll(suffix)
- }
- override def take(n: Int): List[A] = if (isEmpty || n <= 0) Nil else {
- val h = new ::(head, Nil)
- var t = h
- var rest = tail
- var i = 1
- while ({if (rest.isEmpty) return this; i < n}) {
- i += 1
- val nx = new ::(rest.head, Nil)
- t.next = nx
- t = nx
- rest = rest.tail
- }
- releaseFence()
- h
- }
- /**
- * @example {{{
- * // Given a list
- * val letters = List('a','b','c','d','e')
- *
- * // `slice` returns all elements beginning at index `from` and afterwards,
- * // up until index `until` (excluding index `until`.)
- * letters.slice(1,3) // Returns List('b','c')
- * }}}
- */
- override def slice(from: Int, until: Int): List[A] = {
- val lo = scala.math.max(from, 0)
- if (until <= lo || isEmpty) Nil
- else this drop lo take (until - lo)
- }
- override def takeRight(n: Int): List[A] = {
- @tailrec
- def loop(lead: List[A], lag: List[A]): List[A] = lead match {
- case Nil => lag
- case _ :: tail => loop(tail, lag.tail)
- }
- loop(drop(n), this)
- }
- // dropRight is inherited from LinearSeq
- override def splitAt(n: Int): (List[A], List[A]) = {
- val b = new ListBuffer[A]
- var i = 0
- var these = this
- while (!these.isEmpty && i < n) {
- i += 1
- b += these.head
- these = these.tail
- }
- (b.toList, these)
- }
- override def updated[B >: A](index: Int, elem: B): List[B] = {
- var i = 0
- var current = this
- val prefix = ListBuffer.empty[B]
- while (i < index && current.nonEmpty) {
- i += 1
- prefix += current.head
- current = current.tail
- }
- if (i == index && current.nonEmpty) {
- prefix.prependToList(elem :: current.tail)
- } else {
- throw new IndexOutOfBoundsException(s"$index is out of bounds (min 0, max ${length-1})")
- }
- }
- final override def map[B](f: A => B): List[B] = {
- if (this eq Nil) Nil else {
- val h = new ::[B](f(head), Nil)
- var t: ::[B] = h
- var rest = tail
- while (rest ne Nil) {
- val nx = new ::(f(rest.head), Nil)
- t.next = nx
- t = nx
- rest = rest.tail
- }
- releaseFence()
- h
- }
- }
- final override def collect[B](pf: PartialFunction[A, B]): List[B] = {
- if (this eq Nil) Nil else {
- var rest = this
- var h: ::[B] = null
- var x: Any = null
- // Special case for first element
- while (h eq null) {
- x = pf.applyOrElse(rest.head, List.partialNotApplied)
- if (x.asInstanceOf[AnyRef] ne List.partialNotApplied) h = new ::(x.asInstanceOf[B], Nil)
- rest = rest.tail
- if (rest eq Nil) return if (h eq null) Nil else h
- }
- var t = h
- // Remaining elements
- while (rest ne Nil) {
- x = pf.applyOrElse(rest.head, List.partialNotApplied)
- if (x.asInstanceOf[AnyRef] ne List.partialNotApplied) {
- val nx = new ::(x.asInstanceOf[B], Nil)
- t.next = nx
- t = nx
- }
- rest = rest.tail
- }
- releaseFence()
- h
- }
- }
- final override def flatMap[B](f: A => IterableOnce[B]): List[B] = {
- var rest = this
- var h: ::[B] = null
- var t: ::[B] = null
- while (rest ne Nil) {
- val it = f(rest.head).iterator
- while (it.hasNext) {
- val nx = new ::(it.next(), Nil)
- if (t eq null) {
- h = nx
- } else {
- t.next = nx
- }
- t = nx
- }
- rest = rest.tail
- }
- if (h eq null) Nil else {releaseFence(); h}
- }
- @inline final override def takeWhile(p: A => Boolean): List[A] = {
- val b = new ListBuffer[A]
- var these = this
- while (!these.isEmpty && p(these.head)) {
- b += these.head
- these = these.tail
- }
- b.toList
- }
- @inline final override def span(p: A => Boolean): (List[A], List[A]) = {
- val b = new ListBuffer[A]
- var these = this
- while (!these.isEmpty && p(these.head)) {
- b += these.head
- these = these.tail
- }
- (b.toList, these)
- }
- // Overridden with an implementation identical to the inherited one (at this time)
- // solely so it can be finalized and thus inlinable.
- @inline final override def foreach[U](f: A => U): Unit = {
- var these = this
- while (!these.isEmpty) {
- f(these.head)
- these = these.tail
- }
- }
- final override def reverse: List[A] = {
- var result: List[A] = Nil
- var these = this
- while (!these.isEmpty) {
- result = these.head :: result
- these = these.tail
- }
- result
- }
- final override def foldRight[B](z: B)(op: (A, B) => B): B = {
- var acc = z
- var these: List[A] = reverse
- while (!these.isEmpty) {
- acc = op(these.head, acc)
- these = these.tail
- }
- acc
- }
- // Copy/Paste overrides to avoid interface calls inside loops.
- override final def length: Int = {
- var these = this
- var len = 0
- while (!these.isEmpty) {
- len += 1
- these = these.tail
- }
- len
- }
- override final def lengthCompare(len: Int): Int = {
- @tailrec def loop(i: Int, xs: List[A]): Int = {
- if (i == len)
- if (xs.isEmpty) 0 else 1
- else if (xs.isEmpty)
- -1
- else
- loop(i + 1, xs.tail)
- }
- if (len < 0) 1
- else loop(0, coll)
- }
- override final def forall(p: A => Boolean): Boolean = {
- var these: List[A] = this
- while (!these.isEmpty) {
- if (!p(these.head)) return false
- these = these.tail
- }
- true
- }
- override final def exists(p: A => Boolean): Boolean = {
- var these: List[A] = this
- while (!these.isEmpty) {
- if (p(these.head)) return true
- these = these.tail
- }
- false
- }
- override final def contains[A1 >: A](elem: A1): Boolean = {
- var these: List[A] = this
- while (!these.isEmpty) {
- if (these.head == elem) return true
- these = these.tail
- }
- false
- }
- override final def find(p: A => Boolean): Option[A] = {
- var these: List[A] = this
- while (!these.isEmpty) {
- if (p(these.head)) return Some(these.head)
- these = these.tail
- }
- None
- }
- override def last: A = {
- if (isEmpty) throw new NoSuchElementException("List.last")
- else {
- var these = this
- var scout = tail
- while (!scout.isEmpty) {
- these = scout
- scout = scout.tail
- }
- these.head
- }
- }
- override def corresponds[B](that: collection.Seq[B])(p: (A, B) => Boolean): Boolean = that match {
- case that: LinearSeq[B] =>
- var i = this
- var j = that
- while (!(i.isEmpty || j.isEmpty)) {
- if (!p(i.head, j.head))
- return false
- i = i.tail
- j = j.tail
- }
- i.isEmpty && j.isEmpty
- case _ =>
- super.corresponds(that)(p)
- }
- override protected[this] def className = "List"
- /** Builds a new list by applying a function to all elements of this list.
- * Like `xs map f`, but returns `xs` unchanged if function
- * `f` maps all elements to themselves (as determined by `eq`).
- *
- * @param f the function to apply to each element.
- * @tparam B the element type of the returned collection.
- * @return a list resulting from applying the given function
- * `f` to each element of this list and collecting the results.
- */
- @`inline` final def mapConserve[B >: A <: AnyRef](f: A => B): List[B] = {
- // Note to developers: there exists a duplication between this function and `reflect.internal.util.Collections#map2Conserve`.
- // If any successful optimization attempts or other changes are made, please rehash them there too.
- @tailrec
- def loop(mappedHead: List[B], mappedLast: ::[B], unchanged: List[A], pending: List[A]): List[B] = {
- if (pending.isEmpty) {
- if (mappedHead eq null) unchanged
- else {
- mappedLast.next = (unchanged: List[B])
- mappedHead
- }
- }
- else {
- val head0 = pending.head
- val head1 = f(head0)
- if (head1 eq head0.asInstanceOf[AnyRef])
- loop(mappedHead, mappedLast, unchanged, pending.tail)
- else {
- var xc = unchanged
- var mappedHead1: List[B] = mappedHead
- var mappedLast1: ::[B] = mappedLast
- while (xc ne pending) {
- val next = new ::[B](xc.head, Nil)
- if (mappedHead1 eq null) mappedHead1 = next
- if (mappedLast1 ne null) mappedLast1.next = next
- mappedLast1 = next
- xc = xc.tail
- }
- val next = new ::(head1, Nil)
- if (mappedHead1 eq null) mappedHead1 = next
- if (mappedLast1 ne null) mappedLast1.next = next
- mappedLast1 = next
- val tail0 = pending.tail
- loop(mappedHead1, mappedLast1, tail0, tail0)
- }
- }
- }
- val result = loop(null, null, this, this)
- releaseFence()
- result
- }
- override def filter(p: A => Boolean): List[A] = filterCommon(p, isFlipped = false)
- override def filterNot(p: A => Boolean): List[A] = filterCommon(p, isFlipped = true)
- private[this] def filterCommon(p: A => Boolean, isFlipped: Boolean): List[A] = {
- // everything seen so far so far is not included
- @tailrec def noneIn(l: List[A]): List[A] = {
- if (l.isEmpty)
- Nil
- else {
- val h = l.head
- val t = l.tail
- if (p(h) != isFlipped)
- allIn(l, t)
- else
- noneIn(t)
- }
- }
- // everything from 'start' is included, if everything from this point is in we can return the origin
- // start otherwise if we discover an element that is out we must create a new partial list.
- @tailrec def allIn(start: List[A], remaining: List[A]): List[A] = {
- if (remaining.isEmpty)
- start
- else {
- val x = remaining.head
- if (p(x) != isFlipped)
- allIn(start, remaining.tail)
- else
- partialFill(start, remaining)
- }
- }
- // we have seen elements that should be included then one that should be excluded, start building
- def partialFill(origStart: List[A], firstMiss: List[A]): List[A] = {
- val newHead = new ::(origStart.head, Nil)
- var toProcess = origStart.tail
- var currentLast = newHead
- // we know that all elements are :: until at least firstMiss.tail
- while (!(toProcess eq firstMiss)) {
- val newElem = new ::(toProcess.head, Nil)
- currentLast.next = newElem
- currentLast = newElem
- toProcess = toProcess.tail
- }
- // at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss.
- // currentLast is the last element in that list.
- // now we are going to try and share as much of the tail as we can, only moving elements across when we have to.
- var next = firstMiss.tail
- var nextToCopy = next // the next element we would need to copy to our list if we cant share.
- while (!next.isEmpty) {
- // generally recommended is next.isNonEmpty but this incurs an extra method call.
- val head: A = next.head
- if (p(head) != isFlipped) {
- next = next.tail
- } else {
- // its not a match - do we have outstanding elements?
- while (!(nextToCopy eq next)) {
- val newElem = new ::(nextToCopy.head, Nil)
- currentLast.next = newElem
- currentLast = newElem
- nextToCopy = nextToCopy.tail
- }
- nextToCopy = next.tail
- next = next.tail
- }
- }
- // we have remaining elements - they are unchanged attach them to the end
- if (!nextToCopy.isEmpty)
- currentLast.next = nextToCopy
- newHead
- }
- val result = noneIn(this)
- releaseFence()
- result
- }
- override def partition(p: A => Boolean): (List[A], List[A]) = {
- if (isEmpty) List.TupleOfNil
- else super.partition(p) match {
- case (Nil, xs) => (Nil, this)
- case (xs, Nil) => (this, Nil)
- case pair => pair
- }
- }
- final override def toList: List[A] = this
- // Override for performance
- override def equals(o: scala.Any): Boolean = {
- @tailrec def listEq(a: List[_], b: List[_]): Boolean =
- (a eq b) || {
- val aEmpty = a.isEmpty
- val bEmpty = b.isEmpty
- if (!(aEmpty || bEmpty) && a.head == b.head) {
- listEq(a.tail, b.tail)
- }
- else {
- aEmpty && bEmpty
- }
- }
- o match {
- case that: List[_] => listEq(this, that)
- case _ => super.equals(o)
- }
- }
- }
- // Internal code that mutates `next` _must_ call `Statics.releaseFence()` if either immediately, or
- // before a newly-allocated, thread-local :: instance is aliased (e.g. in ListBuffer.toList)
- final case class :: [+A](override val head: A, private[scala] var next: List[A @uncheckedVariance]) // sound because `next` is used only locally
- extends List[A] {
- releaseFence()
- override def headOption: Some[A] = Some(head)
- override def tail: List[A] = next
- }
- case object Nil extends List[Nothing] {
- override def head: Nothing = throw new NoSuchElementException("head of empty list")
- override def headOption: None.type = None
- override def tail: Nothing = throw new UnsupportedOperationException("tail of empty list")
- override def last: Nothing = throw new NoSuchElementException("last of empty list")
- override def init: Nothing = throw new UnsupportedOperationException("init of empty list")
- override def knownSize: Int = 0
- override def iterator: Iterator[Nothing] = Iterator.empty
- override def unzip[A1, A2](implicit asPair: Nothing => (A1, A2)): (List[A1], List[A2]) = EmptyUnzip
- @transient
- private[this] val EmptyUnzip = (Nil, Nil)
- }
- /**
- * $factoryInfo
- * @define coll list
- * @define Coll `List`
- */
- @SerialVersionUID(3L)
- object List extends StrictOptimizedSeqFactory[List] {
- private val TupleOfNil = (Nil, Nil)
- def from[B](coll: collection.IterableOnce[B]): List[B] = Nil.prependedAll(coll)
- def newBuilder[A]: Builder[A, List[A]] = new ListBuffer()
- def empty[A]: List[A] = Nil
- @transient
- private[collection] val partialNotApplied = new Function1[Any, Any] { def apply(x: Any): Any = this }
- }