/*
 * 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.collection

import scala.collection.immutable.Range
import scala.util.hashing.MurmurHash3
import Searching.{Found, InsertionPoint, SearchResult}
import scala.annotation.nowarn

/** Base trait for sequence collections
  *
  * @tparam A the element type of the collection
  */
trait Seq[+A]
  extends Iterable[A]
    with PartialFunction[Int, A]
    with SeqOps[A, Seq, Seq[A]]
    with IterableFactoryDefaults[A, Seq]
    with Equals {

  override def iterableFactory: SeqFactory[Seq] = Seq

  def canEqual(that: Any): Boolean = true

  override def equals(o: Any): Boolean =
    (this eq o.asInstanceOf[AnyRef]) || (o match {
      case seq: Seq[A @unchecked] if seq.canEqual(this) => sameElements(seq)
      case _ => false
    })

  override def hashCode(): Int = MurmurHash3.seqHash(this)

  override def toString(): String = super[Iterable].toString()

  @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
  override protected[this] def stringPrefix: String = "Seq"
}

/**
  * $factoryInfo
  * @define coll sequence
  * @define Coll `Seq`
  */
@SerialVersionUID(3L)
object Seq extends SeqFactory.Delegate[Seq](immutable.Seq)

/** Base trait for Seq operations
  *
  * @tparam A the element type of the collection
  * @tparam CC type constructor of the collection (e.g. `List`, `Set`). Operations returning a collection
  *             with a different type of element `B` (e.g. `map`) return a `CC[B]`.
  * @tparam C  type of the collection (e.g. `List[Int]`, `String`, `BitSet`). Operations returning a collection
  *             with the same type of element (e.g. `drop`, `filter`) return a `C`.
  * @define orderDependent
  * @define orderDependentFold
  * @define mayNotTerminateInf
  *
  *    Note: may not terminate for infinite-sized collections.
  *
  * @define willNotTerminateInf
  *
  *    Note: will not terminate for infinite-sized collections.
  *
  * @define coll sequence
  * @define Coll `Seq`
  */
trait SeqOps[+A, +CC[_], +C] extends Any
  with IterableOps[A, CC, C] { self =>

  override def view: SeqView[A] = new SeqView.Id[A](this)

  /** Gets the element at the specified index. This operation is provided for convenience in `Seq`. It should
    * not be assumed to be efficient unless you have an `IndexedSeq`. */
  @throws[IndexOutOfBoundsException]
  def apply(i: Int): A

  /** The length (number of elements) of the $coll. `size` is an alias for `length` in `Seq` collections. */
  def length: Int

  /** A copy of the $coll with an element prepended.
    *
    * Also, the original $coll is not modified, so you will want to capture the result.
    *
    *    Example:
    *    {{{
    *      scala> val x = List(1)
    *      x: List[Int] = List(1)
    *
    *      scala> val y = 2 +: x
    *      y: List[Int] = List(2, 1)
    *
    *      scala> println(x)
    *      List(1)
    *    }}}
    *
    *  @param  elem   the prepended element
    *  @tparam B      the element type of the returned $coll.
    *
    *    @return a new $coll consisting of `value` followed
    *            by all elements of this $coll.
    */
  def prepended[B >: A](elem: B): CC[B] = iterableFactory.from(new View.Prepended(elem, this))

  /** Alias for `prepended`.
    *
    * Note that :-ending operators are right associative (see example).
    * A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
    */
  @`inline` final def +: [B >: A](elem: B): CC[B] = prepended(elem)

  /** A copy of this $coll with an element appended.
    *
    * $willNotTerminateInf
    *
    * Example:
    * {{{
    *    scala> val a = List(1)
    *    a: List[Int] = List(1)
    *
    *    scala> val b = a :+ 2
    *    b: List[Int] = List(1, 2)
    *
    *    scala> println(a)
    *    List(1)
    * }}}
    *
    * @param  elem   the appended element
    * @tparam B      the element type of the returned $coll.
    * @return a new $coll consisting of
    *         all elements of this $coll followed by `value`.
    */
  def appended[B >: A](elem: B): CC[B] = iterableFactory.from(new View.Appended(this, elem))

  /** Alias for `appended`.
    *
    * Note that :-ending operators are right associative (see example).
    * A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
    */
  @`inline` final def :+ [B >: A](elem: B): CC[B] = appended(elem)

  /** As with `:++`, returns a new collection containing the elements from the left operand followed by the
    *  elements from the right operand.
    *
    *  It differs from `:++` in that the right operand determines the type of
    *  the resulting collection rather than the left one.
    *  Mnemonic: the COLon is on the side of the new COLlection type.
    *
    *  @param prefix   the iterable to prepend.
    *  @tparam B     the element type of the returned collection.
    *  @return       a new $coll which contains all elements of `prefix` followed
    *                  by all the elements of this $coll.
    */
  def prependedAll[B >: A](prefix: IterableOnce[B]): CC[B] = iterableFactory.from(prefix match {
    case prefix: Iterable[B] => new View.Concat(prefix, this)
    case _ => prefix.iterator ++ iterator
  })

  /** Alias for `prependedAll`. */
  @`inline` override final def ++: [B >: A](prefix: IterableOnce[B]): CC[B] = prependedAll(prefix)

  /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
    *  right hand operand. The element type of the $coll is the most specific superclass encompassing
    *  the element types of the two operands.
    *
    *  @param suffix the iterable to append.
    *  @tparam B     the element type of the returned collection.
    *  @return       a new collection of type `CC[B]` which contains all elements
    *                of this $coll followed by all elements of `suffix`.
    */
  def appendedAll[B >: A](suffix: IterableOnce[B]): CC[B] = super.concat(suffix)

  /** Alias for `appendedAll`. */
  @`inline` final def :++ [B >: A](suffix: IterableOnce[B]): CC[B] = appendedAll(suffix)

  // Make `concat` an alias for `appendedAll` so that it benefits from performance
  // overrides of this method
  @`inline` final override def concat[B >: A](suffix: IterableOnce[B]): CC[B] = appendedAll(suffix)

 /** Produces a new sequence which contains all elements of this $coll and also all elements of
   *  a given sequence. `xs union ys`  is equivalent to `xs ++ ys`.
   *
   *  @param that   the sequence to add.
   *  @tparam B     the element type of the returned $coll.
   *  @return       a new collection which contains all elements of this $coll
   *                followed by all elements of `that`.
   */
  @deprecated("Use `concat` instead", "2.13.0")
  @inline final def union[B >: A](that: Seq[B]): CC[B] = concat(that)

  final override def size: Int = length

  /** Selects all the elements of this $coll ignoring the duplicates.
    *
    * @return a new $coll consisting of all the elements of this $coll without duplicates.
    */
  def distinct: C = distinctBy(identity)

  /** Selects all the elements of this $coll ignoring the duplicates as determined by `==` after applying
    * the transforming function `f`.
    *
    * @param f The transforming function whose result is used to determine the uniqueness of each element
    * @tparam B the type of the elements after being transformed by `f`
    * @return a new $coll consisting of all the elements of this $coll without duplicates.
    */
  def distinctBy[B](f: A => B): C = fromSpecific(new View.DistinctBy(this, f))

  /** Returns a new $coll with the elements of this $coll in reverse order.
   *
   *  $willNotTerminateInf
   *  $willForceEvaluation
   *
   *  @return a new $coll with all elements of this $coll in reverse order.
   */
  def reverse: C = fromSpecific(reversed)

  /** An iterator yielding the elements of this $coll in reverse order.
   *
   *   $willNotTerminateInf
   *
   * Note: `xs.reverseIterator` is the same as `xs.reverse.iterator` but might be more efficient.
   *
   *  @return  an iterator yielding the elements of this $coll in reverse order.
   */
  def reverseIterator: Iterator[A] = reversed.iterator

  /** Tests whether this $coll contains the given sequence at a given index.
    *
    * '''Note''': If the both the receiver object `this` and the argument
    * `that` are infinite sequences this method may not terminate.
    *
    * @param  that    the sequence to test
    * @param  offset  the index where the sequence is searched.
    * @return `true` if the sequence `that` is contained in this $coll at
    *         index `offset`, otherwise `false`.
    */
  def startsWith[B >: A](that: IterableOnce[B], offset: Int = 0): Boolean = {
    val i = iterator drop offset
    val j = that.iterator
    while (j.hasNext && i.hasNext)
      if (i.next() != j.next())
        return false

    !j.hasNext
  }

  /** Tests whether this $coll ends with the given sequence.
    *  $willNotTerminateInf
    *  @param  that    the sequence to test
    *  @return `true` if this $coll has `that` as a suffix, `false` otherwise.
    */
  def endsWith[B >: A](that: Iterable[B]): Boolean = {
    if (that.isEmpty) true
    else {
      val i = iterator.drop(length - that.size)
      val j = that.iterator
      while (i.hasNext && j.hasNext)
        if (i.next() != j.next())
          return false

      !j.hasNext
    }
  }

  /** Tests whether this $coll contains given index.
    *
    *  The implementations of methods `apply` and `isDefinedAt` turn a `Seq[A]` into
    *  a `PartialFunction[Int, A]`.
    *
    * @param    idx     the index to test
    * @return   `true` if this $coll contains an element at position `idx`, `false` otherwise.
    */
  def isDefinedAt(idx: Int): Boolean = idx >= 0 && lengthIs > idx

  /** A copy of this $coll with an element value appended until a given target length is reached.
   *
   *  @param   len   the target length
   *  @param   elem  the padding value
   *  @tparam B      the element type of the returned $coll.
   *  @return a new $coll consisting of
   *          all elements of this $coll followed by the minimal number of occurrences of `elem` so
   *          that the resulting collection has a length of at least `len`.
   */
  def padTo[B >: A](len: Int, elem: B): CC[B] = iterableFactory.from(new View.PadTo(this, len, elem))

  /** Computes the length of the longest segment that starts from the first element
    *  and whose elements all satisfy some predicate.
    *
    *  $mayNotTerminateInf
    *
    *  @param   p     the predicate used to test elements.
    *  @return  the length of the longest segment of this $coll that starts from the first element
    *           such that every element of the segment satisfies the predicate `p`.
    */
  final def segmentLength(p: A => Boolean): Int = segmentLength(p, 0)

  /** Computes the length of the longest segment that starts from some index
    *  and whose elements all satisfy some predicate.
    *
    *  $mayNotTerminateInf
    *
    *  @param   p     the predicate used to test elements.
    *  @param   from  the index where the search starts.
    *  @return  the length of the longest segment of this $coll starting from index `from`
    *           such that every element of the segment satisfies the predicate `p`.
    */
  def segmentLength(p: A => Boolean, from: Int): Int = {
    var i = 0
    val it = iterator.drop(from)
    while (it.hasNext && p(it.next()))
      i += 1
    i
  }

  /** Returns the length of the longest prefix whose elements all satisfy some predicate.
    *
    *  $mayNotTerminateInf
    *
    *  @param   p     the predicate used to test elements.
    *  @return  the length of the longest prefix of this $coll
    *           such that every element of the segment satisfies the predicate `p`.
    */
  @deprecated("Use segmentLength instead of prefixLength", "2.13.0")
  @`inline` final def prefixLength(p: A => Boolean): Int = segmentLength(p, 0)

  /** Finds index of the first element satisfying some predicate after or at some start index.
    *
    *  $mayNotTerminateInf
    *
    *  @param   p     the predicate used to test elements.
    *  @param   from   the start index
    *  @return  the index `>= from` of the first element of this $coll that satisfies the predicate `p`,
    *           or `-1`, if none exists.
    */
  def indexWhere(p: A => Boolean, from: Int): Int = iterator.indexWhere(p, from)

  /** Finds index of the first element satisfying some predicate.
    *
    *  $mayNotTerminateInf
    *
    *  @param   p     the predicate used to test elements.
    *  @return  the index `>= 0` of the first element of this $coll that satisfies the predicate `p`,
    *           or `-1`, if none exists.
    */
  @deprecatedOverriding("Override indexWhere(p, from) instead - indexWhere(p) calls indexWhere(p, 0)", "2.13.0")
  def indexWhere(p: A => Boolean): Int = indexWhere(p, 0)

  /** Finds index of first occurrence of some value in this $coll after or at some start index.
    *
    *  @param   elem   the element value to search for.
    *  @tparam  B      the type of the element `elem`.
    *  @param   from   the start index
    *  @return  the index `>= from` of the first element of this $coll that is equal (as determined by `==`)
    *           to `elem`, or `-1`, if none exists.
    */
  def indexOf[B >: A](elem: B, from: Int): Int = indexWhere(elem == _, from)

  /** Finds index of first occurrence of some value in this $coll.
    *
    *  @param   elem   the element value to search for.
    *  @tparam  B      the type of the element `elem`.
    *  @return  the index `>= 0` of the first element of this $coll that is equal (as determined by `==`)
    *           to `elem`, or `-1`, if none exists.
    */
  @deprecatedOverriding("Override indexOf(elem, from) instead - indexOf(elem) calls indexOf(elem, 0)", "2.13.0")
  def indexOf[B >: A](elem: B): Int = indexOf(elem, 0)

  /** Finds index of last occurrence of some value in this $coll before or at a given end index.
   *
   *  $willNotTerminateInf
   *
   *  @param   elem   the element value to search for.
   *  @param   end    the end index.
   *  @tparam  B      the type of the element `elem`.
   *  @return  the index `<= end` of the last element of this $coll that is equal (as determined by `==`)
   *           to `elem`, or `-1`, if none exists.
   */
  def lastIndexOf[B >: A](elem: B, end: Int = length - 1): Int = lastIndexWhere(elem == _, end)

  /** Finds index of last element satisfying some predicate before or at given end index.
   *
   *  $willNotTerminateInf
   *
   *  @param   p     the predicate used to test elements.
   *  @return  the index `<= end` of the last element of this $coll that satisfies the predicate `p`,
   *           or `-1`, if none exists.
   */
  def lastIndexWhere(p: A => Boolean, end: Int): Int = {
    var i = length - 1
    val it = reverseIterator
    while (it.hasNext && { val elem = it.next(); (i > end || !p(elem)) }) i -= 1
    i
  }

  /** Finds index of last element satisfying some predicate.
   *
   *  $willNotTerminateInf
   *
   *  @param   p     the predicate used to test elements.
   *  @return  the index of the last element of this $coll that satisfies the predicate `p`,
   *           or `-1`, if none exists.
   */
  @deprecatedOverriding("Override lastIndexWhere(p, end) instead - lastIndexWhere(p) calls lastIndexWhere(p, Int.MaxValue)", "2.13.0")
  def lastIndexWhere(p: A => Boolean): Int = lastIndexWhere(p, Int.MaxValue)

  @inline private[this] def toGenericSeq: scala.collection.Seq[A] = this match {
    case s: scala.collection.Seq[A] => s
    case _ => toSeq
  }

  /** Finds first index after or at a start index where this $coll contains a given sequence as a slice.
   *  $mayNotTerminateInf
   *  @param  that    the sequence to test
   *  @param  from    the start index
   *  @return  the first index `>= from` such that the elements of this $coll starting at this index
   *           match the elements of sequence `that`, or `-1` if no such subsequence exists.
   */
  // TODO Should be implemented in a way that preserves laziness
  def indexOfSlice[B >: A](that: Seq[B], from: Int): Int =
    if (that.isEmpty && from == 0) 0
    else {
      val l = knownSize
      val tl = that.knownSize
      if (l >= 0 && tl >= 0) {
        val clippedFrom = math.max(0, from)
        if (from > l) -1
        else if (tl < 1) clippedFrom
        else if (l < tl) -1
        else SeqOps.kmpSearch(toGenericSeq, clippedFrom, l, that, 0, tl, forward = true)
      }
      else {
        var i = from
        var s: scala.collection.Seq[A] = toGenericSeq.drop(i)
        while (!s.isEmpty) {
          if (s startsWith that)
            return i

          i += 1
          s = s.tail
        }
        -1
      }
    }

  /** Finds first index where this $coll contains a given sequence as a slice.
    *  $mayNotTerminateInf
    *  @param  that    the sequence to test
    *  @return  the first index `>= 0` such that the elements of this $coll starting at this index
    *           match the elements of sequence `that`, or `-1` if no such subsequence exists.
    */
  @deprecatedOverriding("Override indexOfSlice(that, from) instead - indexOfSlice(that) calls indexOfSlice(that, 0)", "2.13.0")
  def indexOfSlice[B >: A](that: Seq[B]): Int = indexOfSlice(that, 0)

  /** Finds last index before or at a given end index where this $coll contains a given sequence as a slice.
   *
   *  $willNotTerminateInf
   *
   *  @param  that    the sequence to test
   *  @param  end     the end index
   *  @return  the last index `<= end` such that the elements of this $coll starting at this index
   *           match the elements of sequence `that`, or `-1` if no such subsequence exists.
   */
  def lastIndexOfSlice[B >: A](that: Seq[B], end: Int): Int = {
    val l = length
    val tl = that.length
    val clippedL = math.min(l-tl, end)

    if (end < 0) -1
    else if (tl < 1) clippedL
    else if (l < tl) -1
    else SeqOps.kmpSearch(toGenericSeq, 0, clippedL+tl, that, 0, tl, forward = false)
  }

  /** Finds last index where this $coll contains a given sequence as a slice.
    *
    *  $willNotTerminateInf
    *
    *  @param  that    the sequence to test
    *  @return  the last index such that the elements of this $coll starting at this index
    *           match the elements of sequence `that`, or `-1` if no such subsequence exists.
    */
  @deprecatedOverriding("Override lastIndexOfSlice(that, end) instead - lastIndexOfSlice(that) calls lastIndexOfSlice(that, Int.MaxValue)", "2.13.0")
  def lastIndexOfSlice[B >: A](that: Seq[B]): Int = lastIndexOfSlice(that, Int.MaxValue)

  /** Finds the last element of the $coll satisfying a predicate, if any.
   *
   *  $willNotTerminateInf
   *
   *  @param p       the predicate used to test elements.
   *  @return        an option value containing the last element in the $coll
   *                 that satisfies `p`, or `None` if none exists.
   */
  def findLast(p: A => Boolean): Option[A] = {
    val it = reverseIterator
    while (it.hasNext) {
      val elem = it.next()
      if (p(elem)) return Some(elem)
    }
    None
  }

  /** Tests whether this $coll contains a given sequence as a slice.
   *  $mayNotTerminateInf
   *  @param  that    the sequence to test
   *  @return  `true` if this $coll contains a slice with the same elements
   *           as `that`, otherwise `false`.
   */
  def containsSlice[B >: A](that: Seq[B]): Boolean = indexOfSlice(that) != -1

  /** Tests whether this $coll contains a given value as an element.
   *  $mayNotTerminateInf
   *
   *  @param elem  the element to test.
   *  @return     `true` if this $coll has an element that is equal (as
   *              determined by `==`) to `elem`, `false` otherwise.
   */
  def contains[A1 >: A](elem: A1): Boolean = exists (_ == elem)

  @deprecated("Use .reverseIterator.map(f).to(...) instead of .reverseMap(f)", "2.13.0")
  def reverseMap[B](f: A => B): CC[B] = iterableFactory.from(new View.Map(View.fromIteratorProvider(() => reverseIterator), f))

  /** Iterates over distinct permutations of elements.
   *
   *  $willForceEvaluation
   *
   *  @return   An Iterator which traverses the distinct permutations of this $coll.
   *  @example {{{
   *    Seq('a', 'b', 'b').permutations.foreach(println)
   *    // List(a, b, b)
   *    // List(b, a, b)
   *    // List(b, b, a)
   *  }}}
   */
  def permutations: Iterator[C] =
    if (isEmpty) Iterator.single(coll)
    else new PermutationsItr

  /** Iterates over combinations of elements.
   *
   *  A '''combination''' of length `n` is a sequence of `n` elements selected in order of their first index in this sequence.
   *
   *  For example, `"xyx"` has two combinations of length 2. The `x` is selected first: `"xx"`, `"xy"`.
   *  The sequence `"yx"` is not returned as a combination because it is subsumed by `"xy"`.
   *
   *  If there is more than one way to generate the same combination, only one will be returned.
   *
   *  For example, the result `"xy"` arbitrarily selected one of the `x` elements.
   *
   *  As a further illustration, `"xyxx"` has three different ways to generate `"xy"` because there are three elements `x`
   *  to choose from. Moreover, there are three unordered pairs `"xx"` but only one is returned.
   *
   *  It is not specified which of these equal combinations is returned. It is an implementation detail
   *  that should not be relied on. For example, the combination `"xx"` does not necessarily contain
   *  the first `x` in this sequence. This behavior is observable if the elements compare equal
   *  but are not identical.
   *
   *  As a consequence, `"xyx".combinations(3).next()` is `"xxy"`: the combination does not reflect the order
   *  of the original sequence, but the order in which elements were selected, by "first index";
   *  the order of each `x` element is also arbitrary.
   *
   *  $willForceEvaluation
   *
   *  @return   An Iterator which traverses the n-element combinations of this $coll.
   *  @example {{{
   *    Seq('a', 'b', 'b', 'b', 'c').combinations(2).foreach(println)
   *    // List(a, b)
   *    // List(a, c)
   *    // List(b, b)
   *    // List(b, c)
   *    Seq('b', 'a', 'b').combinations(2).foreach(println)
   *    // List(b, b)
   *    // List(b, a)
   *  }}}
   */
  def combinations(n: Int): Iterator[C] =
    if (n < 0 || n > size) Iterator.empty
    else new CombinationsItr(n)

  private class PermutationsItr extends AbstractIterator[C] {
    private[this] val (elms, idxs) = init()
    private[this] var _hasNext = true

    def hasNext = _hasNext
    @throws[NoSuchElementException]
    def next(): C = {
      if (!hasNext)
        Iterator.empty.next()

      val forcedElms = new mutable.ArrayBuffer[A](elms.size) ++= elms
      val result = (newSpecificBuilder ++= forcedElms).result()
      var i = idxs.length - 2
      while(i >= 0 && idxs(i) >= idxs(i+1))
        i -= 1

      if (i < 0)
        _hasNext = false
      else {
        var j = idxs.length - 1
        while(idxs(j) <= idxs(i)) j -= 1
        swap(i,j)

        val len = (idxs.length - i) / 2
        var k = 1
        while (k <= len) {
          swap(i+k, idxs.length - k)
          k += 1
        }
      }
      result
    }
    private def swap(i: Int, j: Int): Unit = {
      val tmpI = idxs(i)
      idxs(i) = idxs(j)
      idxs(j) = tmpI
      val tmpE = elms(i)
      elms(i) = elms(j)
      elms(j) = tmpE
    }

    private[this] def init() = {
      val m = mutable.HashMap[A, Int]()
      val (es, is) = (self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2)).unzip

      (es.to(mutable.ArrayBuffer), is.toArray)
    }
  }

  private class CombinationsItr(n: Int) extends AbstractIterator[C] {
    // generating all nums such that:
    // (1) nums(0) + .. + nums(length-1) = n
    // (2) 0 <= nums(i) <= cnts(i), where 0 <= i <= cnts.length-1
    private[this] val (elms, cnts, nums) = init()
    private[this] val offs = cnts.scanLeft(0)(_ + _)
    private[this] var _hasNext = true

    def hasNext = _hasNext
    def next(): C = {
      if (!hasNext)
        Iterator.empty.next()

      /* Calculate this result. */
      val buf = newSpecificBuilder
      for(k <- 0 until nums.length; j <- 0 until nums(k))
        buf += elms(offs(k)+j)
      val res = buf.result()

      /* Prepare for the next call to next. */
      var idx = nums.length - 1
      while (idx >= 0 && nums(idx) == cnts(idx))
        idx -= 1

      idx = nums.lastIndexWhere(_ > 0, idx - 1)

      if (idx < 0)
        _hasNext = false
      else {
        // OPT: hand rolled version of `sum = nums.view(idx + 1, nums.length).sum + 1`
        var sum = 1
        var i = idx + 1
        while (i < nums.length) {
          sum += nums(i)
          i += 1
        }
        nums(idx) -= 1
        for (k <- (idx+1) until nums.length) {
          nums(k) = sum min cnts(k)
          sum -= nums(k)
        }
      }

      res
    }

    /** Rearrange seq to newSeq a0a0..a0a1..a1...ak..ak such that
      *  seq.count(_ == aj) == cnts(j)
      *
      *  @return     (newSeq,cnts,nums)
      */
    private def init(): (IndexedSeq[A], Array[Int], Array[Int]) = {
      val m = mutable.HashMap[A, Int]()

      // e => (e, weight(e))
      val (es, is) = (self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2)).unzip
      val cs = new Array[Int](m.size)
      is foreach (i => cs(i) += 1)
      val ns = new Array[Int](cs.length)

      var r = n
      0 until ns.length foreach { k =>
        ns(k) = r min cs(k)
        r -= ns(k)
      }
      (es.to(IndexedSeq), cs, ns)
    }
  }

  /** Sorts this $coll according to an Ordering.
    *
    *  The sort is stable. That is, elements that are equal (as determined by
    *  `ord.compare`) appear in the same order in the sorted sequence as in the original.
    *
    *  @see [[scala.math.Ordering]]
    *
    *  $willForceEvaluation
    *
    *  @param  ord the ordering to be used to compare elements.
    *  @return     a $coll consisting of the elements of this $coll
    *              sorted according to the ordering `ord`.
    */
  def sorted[B >: A](implicit ord: Ordering[B]): C = {
    val len = this.length
    val b = newSpecificBuilder
    if (len == 1) b += head
    else if (len > 1) {
      b.sizeHint(len)
      val arr = new Array[Any](len)
      @annotation.unused val copied = copyToArray(arr)
      //assert(copied == len)
      java.util.Arrays.sort(arr.asInstanceOf[Array[AnyRef]], ord.asInstanceOf[Ordering[AnyRef]])
      var i = 0
      while (i < len) {
        b += arr(i).asInstanceOf[A]
        i += 1
      }
    }
    b.result()
  }

  /** Sorts this $coll according to a comparison function.
   *  $willNotTerminateInf
   *  $willForceEvaluation
   *
   *  The sort is stable. That is, elements that are equal
   *  (`lt` returns false for both directions of comparison)
   *  appear in the same order in the sorted sequence as in the original.
   *
   *  @param  lt  a predicate that is true if
   *              its first argument strictly precedes its second argument in
   *              the desired ordering.
   *  @return     a $coll consisting of the elements of this $coll
   *              sorted according to the comparison function `lt`.
   *  @example {{{
   *    List("Steve", "Bobby", "Tom", "John", "Bob").sortWith((x, y) => x.take(3).compareTo(y.take(3)) < 0) =
   *    List("Bobby", "Bob", "John", "Steve", "Tom")
   *  }}}
   */
  def sortWith(lt: (A, A) => Boolean): C = sorted(Ordering.fromLessThan(lt))

  /** Sorts this $coll according to the Ordering which results from transforming
    * an implicitly given Ordering with a transformation function.
    * $willNotTerminateInf
    * $willForceEvaluation
    *
    * The sort is stable. That is, elements that are equal (as determined by
    * `ord.compare`) appear in the same order in the sorted sequence as in the original.
    *
    *  @see [[scala.math.Ordering]]
    *  @param   f the transformation function mapping elements
    *           to some other domain `B`.
    *  @param   ord the ordering assumed on domain `B`.
    *  @tparam  B the target type of the transformation `f`, and the type where
    *           the ordering `ord` is defined.
    *  @return  a $coll consisting of the elements of this $coll
    *           sorted according to the ordering where `x < y` if
    *           `ord.lt(f(x), f(y))`.
    *
    *  @example {{{
    *    val words = "The quick brown fox jumped over the lazy dog".split(' ')
    *    // this works because scala.Ordering will implicitly provide an Ordering[Tuple2[Int, Char]]
    *    words.sortBy(x => (x.length, x.head))
    *    res0: Array[String] = Array(The, dog, fox, the, lazy, over, brown, quick, jumped)
    *  }}}
    */
  def sortBy[B](f: A => B)(implicit ord: Ordering[B]): C = sorted(ord on f)

  /** Produces the range of all indices of this sequence.
    * $willForceEvaluation
    *
    *  @return  a `Range` value from `0` to one less than the length of this $coll.
    */
  def indices: Range = Range(0, length)

  override final def sizeCompare(otherSize: Int): Int = lengthCompare(otherSize)

  /** Compares the length of this $coll to a test value.
    *
    *   @param   len   the test value that gets compared with the length.
    *   @return  A value `x` where
    *   {{{
    *        x <  0       if this.length <  len
    *        x == 0       if this.length == len
    *        x >  0       if this.length >  len
    *   }}}
    *  The method as implemented here does not call `length` directly; its running time
    *  is `O(length min len)` instead of `O(length)`. The method should be overridden
    *  if computing `length` is cheap and `knownSize` returns `-1`.
    *
    *  @see [[lengthIs]]
    */
  def lengthCompare(len: Int): Int = super.sizeCompare(len)

  override final def sizeCompare(that: Iterable[_]): Int = lengthCompare(that)

  /** Compares the length of this $coll to the size of another `Iterable`.
    *
    *   @param   that the `Iterable` whose size is compared with this $coll's length.
    *   @return  A value `x` where
    *   {{{
    *        x <  0       if this.length <  that.size
    *        x == 0       if this.length == that.size
    *        x >  0       if this.length >  that.size
    *   }}}
    *  The method as implemented here does not call `length` or `size` directly; its running time
    *  is `O(this.length min that.size)` instead of `O(this.length + that.size)`.
    *  The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`.
    */
  def lengthCompare(that: Iterable[_]): Int = super.sizeCompare(that)

  /** Returns a value class containing operations for comparing the length of this $coll to a test value.
    *
    * These operations are implemented in terms of [[lengthCompare(Int) `lengthCompare(Int)`]], and
    * allow the following more readable usages:
    *
    * {{{
    * this.lengthIs < len     // this.lengthCompare(len) < 0
    * this.lengthIs <= len    // this.lengthCompare(len) <= 0
    * this.lengthIs == len    // this.lengthCompare(len) == 0
    * this.lengthIs != len    // this.lengthCompare(len) != 0
    * this.lengthIs >= len    // this.lengthCompare(len) >= 0
    * this.lengthIs > len     // this.lengthCompare(len) > 0
    * }}}
    */
  @inline final def lengthIs: IterableOps.SizeCompareOps = new IterableOps.SizeCompareOps(this)

  override def isEmpty: Boolean = lengthCompare(0) == 0

  /** Tests whether the elements of this collection are the same (and in the same order)
    * as those of `that`.
    */
  def sameElements[B >: A](that: IterableOnce[B]): Boolean = {
    val thisKnownSize = knownSize
    val knownSizeDifference = thisKnownSize != -1 && {
      val thatKnownSize = that.knownSize
      thatKnownSize != -1 && thisKnownSize != thatKnownSize
    }
    !knownSizeDifference && iterator.sameElements(that)
  }

  /** Tests whether every element of this $coll relates to the
    * corresponding element of another sequence by satisfying a test predicate.
    *
    *  @param   that  the other sequence
    *  @param   p     the test predicate, which relates elements from both sequences
    *  @tparam  B     the type of the elements of `that`
    *  @return  `true` if both sequences have the same length and
    *                  `p(x, y)` is `true` for all corresponding elements `x` of this $coll
    *                  and `y` of `that`, otherwise `false`.
    */
  def corresponds[B](that: Seq[B])(p: (A, B) => Boolean): Boolean = {
    val i = iterator
    val j = that.iterator
    while (i.hasNext && j.hasNext)
      if (!p(i.next(), j.next()))
        return false
    !i.hasNext && !j.hasNext
  }

  /** Computes the multiset difference between this $coll and another sequence.
    *
    *  @param that   the sequence of elements to remove
    *  @return       a new $coll which contains all elements of this $coll
    *                except some of occurrences of elements that also appear in `that`.
    *                If an element value `x` appears
    *                ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
    *                part of the result, but any following occurrences will.
    */
  def diff[B >: A](that: Seq[B]): C = {
    val occ = occCounts(that)
    fromSpecific(iterator.filter { x =>
      var include = false
      occ.updateWith(x) {
        case None => {
          include = true
          None
        }
        case Some(1) => None
        case Some(n) => Some(n - 1)
      }
      include
    })
  }

  /** Computes the multiset intersection between this $coll and another sequence.
    *
    *  @param that   the sequence of elements to intersect with.
    *  @return       a new $coll which contains all elements of this $coll
    *                which also appear in `that`.
    *                If an element value `x` appears
    *                ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
    *                in the result, but any following occurrences will be omitted.
    */
  def intersect[B >: A](that: Seq[B]): C = {
    val occ = occCounts(that)
    fromSpecific(iterator.filter { x =>
      var include = true
      occ.updateWith(x) {
        case None => {
          include = false
          None
        }
        case Some(1) => None
        case Some(n) => Some(n - 1)
      }
      include
    })
  }

  /** Produces a new $coll where a slice of elements in this $coll is replaced by another sequence.
    *
    * Patching at negative indices is the same as patching starting at 0.
    * Patching at indices at or larger than the length of the original $coll appends the patch to the end.
    * If the `replaced` count would exceed the available elements, the difference in excess is ignored.
    *
    *  @param  from     the index of the first replaced element
    *  @param  other    the replacement sequence
    *  @param  replaced the number of elements to drop in the original $coll
    *  @tparam B        the element type of the returned $coll.
    *  @return          a new $coll consisting of all elements of this $coll
    *                   except that `replaced` elements starting from `from` are replaced
    *                   by all the elements of `other`.
    */
  def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): CC[B] =
    iterableFactory.from(new View.Patched(this, from, other, replaced))

  /** A copy of this $coll with one single replaced element.
    *  @param  index  the position of the replacement
    *  @param  elem   the replacing element
    *  @tparam B        the element type of the returned $coll.
    *  @return a new $coll which is a copy of this $coll with the element at position `index` replaced by `elem`.
    *  @throws IndexOutOfBoundsException if `index` does not satisfy `0 <= index < length`. In case of a
    *                                    lazy collection this exception may be thrown at a later time or not at
    *                                    all (if the end of the collection is never evaluated).
    */
  def updated[B >: A](index: Int, elem: B): CC[B] = {
    if(index < 0) throw new IndexOutOfBoundsException(index.toString)
    val k = knownSize
    if(k >= 0 && index >= k) throw new IndexOutOfBoundsException(index.toString)
    iterableFactory.from(new View.Updated(this, index, elem))
  }

  protected[collection] def occCounts[B](sq: Seq[B]): mutable.Map[B, Int] = {
    val occ = new mutable.HashMap[B, Int]()
    for (y <- sq) occ.updateWith(y) {
      case None => Some(1)
      case Some(n) => Some(n + 1)
    }
    occ
  }

  /** Searches this sorted sequence for a specific element. If the sequence is an
    * `IndexedSeq`, a binary search is used. Otherwise, a linear search is used.
    *
    * The sequence should be sorted with the same `Ordering` before calling; otherwise,
    * the results are undefined.
    *
    * @see [[scala.collection.IndexedSeq]]
    * @see [[scala.math.Ordering]]
    * @see [[scala.collection.SeqOps]], method `sorted`
    *
    * @param elem the element to find.
    * @param ord  the ordering to be used to compare elements.
    *
    * @return a `Found` value containing the index corresponding to the element in the
    *         sequence, or the `InsertionPoint` where the element would be inserted if
    *         the element is not in the sequence.
    */
  def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult =
    linearSearch(view, elem, 0)(ord)

  /** Searches within an interval in this sorted sequence for a specific element. If this
    * sequence is an `IndexedSeq`, a binary search is used. Otherwise, a linear search
    * is used.
    *
    * The sequence should be sorted with the same `Ordering` before calling; otherwise,
    * the results are undefined.
    *
    * @see [[scala.collection.IndexedSeq]]
    * @see [[scala.math.Ordering]]
    * @see [[scala.collection.SeqOps]], method `sorted`
    *
    * @param elem the element to find.
    * @param from the index where the search starts.
    * @param to   the index following where the search ends.
    * @param ord  the ordering to be used to compare elements.
    *
    * @return a `Found` value containing the index corresponding to the element in the
    *         sequence, or the `InsertionPoint` where the element would be inserted if
    *         the element is not in the sequence.
    * 
    * @note if `to <= from`, the search space is empty, and an `InsertionPoint` at `from`
    *       is returned
    */
  def search[B >: A](elem: B, from: Int, to: Int) (implicit ord: Ordering[B]): SearchResult = 
    linearSearch(view.slice(from, to), elem, math.max(0, from))(ord)

  private[this] def linearSearch[B >: A](c: View[A], elem: B, offset: Int)
                                        (implicit ord: Ordering[B]): SearchResult = {
    var idx = offset
    val it = c.iterator
    while (it.hasNext) {
      val cur = it.next()
      if (ord.equiv(elem, cur)) return Found(idx)
      else if (ord.lt(elem, cur)) return InsertionPoint(idx)
      idx += 1
    }
    InsertionPoint(idx)
  }
}

object SeqOps {

  // KMP search utilities

 /**  A KMP implementation, based on the undoubtedly reliable wikipedia entry.
   *  Note: I made this private to keep it from entering the API.  That can be reviewed.
   *
   *  @param  S       Sequence that may contain target
   *  @param  m0      First index of S to consider
   *  @param  m1      Last index of S to consider (exclusive)
   *  @param  W       Target sequence
   *  @param  n0      First index of W to match
   *  @param  n1      Last index of W to match (exclusive)
   *  @param  forward Direction of search (from beginning==true, from end==false)
   *  @return Index of start of sequence if found, -1 if not (relative to beginning of S, not m0).
   */
  private def kmpSearch[B](S: scala.collection.Seq[B], m0: Int, m1: Int, W: scala.collection.Seq[B], n0: Int, n1: Int, forward: Boolean): Int = {
    // Check for redundant case when target has single valid element
    def clipR(x: Int, y: Int) = if (x < y) x else -1
    def clipL(x: Int, y: Int) = if (x > y) x else -1

    if (n1 == n0+1) {
      if (forward)
        clipR(S.indexOf(W(n0), m0), m1)
      else
        clipL(S.lastIndexOf(W(n0), m1-1), m0-1)
    }

    // Check for redundant case when both sequences are same size
    else if (m1-m0 == n1-n0) {
      // Accepting a little slowness for the uncommon case.
      if (S.iterator.slice(m0, m1).sameElements(W.iterator.slice(n0, n1))) m0
      else -1
    }
    // Now we know we actually need KMP search, so do it
    else S match {
      case xs: scala.collection.IndexedSeq[_] =>
        // We can index into S directly; it should be adequately fast
        val Wopt = kmpOptimizeWord(W, n0, n1, forward)
        val T = kmpJumpTable(Wopt, n1-n0)
        var i, m = 0
        val zero = if (forward) m0 else m1-1
        val delta = if (forward) 1 else -1
        while (i+m < m1-m0) {
          if (Wopt(i) == S(zero+delta*(i+m))) {
            i += 1
            if (i == n1-n0) return (if (forward) m+m0 else m1-m-i)
          }
          else {
            val ti = T(i)
            m += i - ti
            if (i > 0) i = ti
          }
        }
        -1
      case _ =>
        // We had better not index into S directly!
        val iter = S.iterator.drop(m0)
        val Wopt = kmpOptimizeWord(W, n0, n1, forward = true)
        val T = kmpJumpTable(Wopt, n1-n0)
        val cache = new Array[AnyRef](n1-n0)  // Ring buffer--need a quick way to do a look-behind
        var largest = 0
        var i, m = 0
        var answer = -1
        while (m+m0+n1-n0 <= m1) {
          while (i+m >= largest) {
            cache(largest%(n1-n0)) = iter.next().asInstanceOf[AnyRef]
            largest += 1
          }
          if (Wopt(i) == cache((i+m)%(n1-n0)).asInstanceOf[B]) {
            i += 1
            if (i == n1-n0) {
              if (forward) return m+m0
              else {
                i -= 1
                answer = m+m0
                val ti = T(i)
                m += i - ti
                if (i > 0) i = ti
              }
            }
          }
          else {
            val ti = T(i)
            m += i - ti
            if (i > 0) i = ti
          }
        }
        answer
    }
  }

  /** Make sure a target sequence has fast, correctly-ordered indexing for KMP.
   *
   *  @param  W    The target sequence
   *  @param  n0   The first element in the target sequence that we should use
   *  @param  n1   The far end of the target sequence that we should use (exclusive)
   *  @return Target packed in an IndexedSeq (taken from iterator unless W already is an IndexedSeq)
   */
  private def kmpOptimizeWord[B](W: scala.collection.Seq[B], n0: Int, n1: Int, forward: Boolean): IndexedSeqView[B] = W match {
    case iso: IndexedSeq[B] =>
      // Already optimized for indexing--use original (or custom view of original)
      if (forward && n0==0 && n1==W.length) iso.view
      else if (forward) new AbstractIndexedSeqView[B] {
        val length = n1 - n0
        def apply(x: Int) = iso(n0 + x)
      }
      else new AbstractIndexedSeqView[B] {
        def length = n1 - n0
        def apply(x: Int) = iso(n1 - 1 - x)
      }
    case _ =>
      // W is probably bad at indexing.  Pack in array (in correct orientation)
      // Would be marginally faster to special-case each direction
      new AbstractIndexedSeqView[B] {
        private[this] val Warr = new Array[AnyRef](n1-n0)
        private[this] val delta = if (forward) 1 else -1
        private[this] val done = if (forward) n1-n0 else -1
        val wit = W.iterator.drop(n0)
        var i = if (forward) 0 else (n1-n0-1)
        while (i != done) {
          Warr(i) = wit.next().asInstanceOf[AnyRef]
          i += delta
        }

        val length = n1 - n0
        def apply(x: Int) = Warr(x).asInstanceOf[B]
      }
  }

 /** Make a jump table for KMP search.
   *
   *  @param  Wopt The target sequence
   *  @param  wlen Just in case we're only IndexedSeq and not IndexedSeqOptimized
   *  @return KMP jump table for target sequence
   */
  private def kmpJumpTable[B](Wopt: IndexedSeqView[B], wlen: Int) = {
    val arr = new Array[Int](wlen)
    var pos = 2
    var cnd = 0
    arr(0) = -1
    arr(1) = 0
    while (pos < wlen) {
      if (Wopt(pos-1) == Wopt(cnd)) {
        arr(pos) = cnd + 1
        pos += 1
        cnd += 1
      }
      else if (cnd > 0) {
        cnd = arr(cnd)
      }
      else {
        arr(pos) = 0
        pos += 1
      }
    }
    arr
  }
}

/** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */
abstract class AbstractSeq[+A] extends AbstractIterable[A] with Seq[A]
