org.scalactic.Chain.scala Maven / Gradle / Ivy
/*
* Copyright 2001-2013 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalactic
import scala.collection.immutable
import scala.collection.mutable.ArrayBuffer
import scala.collection.GenTraversableOnce
import scala.reflect.ClassTag
import scala.collection.mutable.Buffer
import scala.collection.GenSeq
import scala.collection.GenIterable
import scala.collection.generic.CanBuildFrom
import scala.annotation.unchecked.{ uncheckedVariance => uV }
// Can't be a LinearSeq[T] because Builder would be able to create an empty one.
/**
* A non-empty list: an ordered, immutable, non-empty collection of elements with LinearSeq performance characteristics.
*
*
* The purpose of Chain is to allow you to express in a type that a List is non-empty, thereby eliminating the
* need for (and potential exception from) a run-time check for non-emptiness. For a non-empty sequence with IndexedSeq
* performance, see Every.
*
*
* Constructing Chains
*
*
* You can construct a Chain by passing one or more elements to the Chain.apply factory method:
*
*
*
* scala> Chain(1, 2, 3)
* res0: org.scalactic.Chain[Int] = Chain(1, 2, 3)
*
*
*
* Alternatively you can cons elements onto the End singleton object, similar to making a List starting with Nil:
*
*
*
* scala> 1 :: 2 :: 3 :: Nil
* res0: List[Int] = List(1, 2, 3)
*
* scala> 1 :: 2 :: 3 :: End
* res1: org.scalactic.Chain[Int] = Chain(1, 2, 3)
*
*
*
* Note that although Nil is a List[Nothing], End is
* not a Chain[Nothing], because no empty Chain exists. (A chain is a series
* of connected links; if you have no links, you have no chain.)
*
*
*
* scala> val nil: List[Nothing] = Nil
* nil: List[Nothing] = List()
*
* scala> val nada: Chain[Nothing] = End
* <console>:16: error: type mismatch;
* found : org.scalactic.End.type
* required: org.scalactic.Chain[Nothing]
* val nada: Chain[Nothing] = End
* ^
*
*
* Working with Chains
*
*
* Chain does not extend Scala's Seq or Traversable traits because these require that
* implementations may be empty. For example, if you invoke tail on a Seq that contains just one element,
* you'll get an empty Seq:
*
*
*
* scala> List(1).tail
* res6: List[Int] = List()
*
*
*
* On the other hand, many useful methods exist on Seq that when invoked on a non-empty Seq are guaranteed
* to not result in an empty Seq. For convenience, Chain defines a method corresponding to every such Seq
* method. Here are some examples:
*
*
*
* Chain(1, 2, 3).map(_ + 1) // Result: Chain(2, 3, 4)
* Chain(1).map(_ + 1) // Result: Chain(2)
* Chain(1, 2, 3).containsSlice(Chain(2, 3)) // Result: true
* Chain(1, 2, 3).containsSlice(Chain(3, 4)) // Result: false
* Chain(-1, -2, 3, 4, 5).minBy(_.abs) // Result: -1
*
*
*
* Chain does not currently define any methods corresponding to Seq methods that could result in
* an empty Seq. However, an implicit converison from Chain to List
* is defined in the Chain companion object that will be applied if you attempt to call one of the missing methods. As a
* result, you can invoke filter on an Chain, even though filter could result
* in an empty sequence—but the result type will be List instead of Chain:
*
*
*
* Chain(1, 2, 3).filter(_ < 10) // Result: List(1, 2, 3)
* Chain(1, 2, 3).filter(_ > 10) // Result: List()
*
*
*
*
* You can use Chains in for expressions. The result will be an Chain unless
* you use a filter (an if clause). Because filters are desugared to invocations of filter, the
* result type will switch to a List at that point. Here are some examples:
*
*
*
* scala> import org.scalactic._
* import org.scalactic._
*
* scala> for (i <- Chain(1, 2, 3)) yield i + 1
* res0: org.scalactic.Chain[Int] = Chain(2, 3, 4)
*
* scala> for (i <- Chain(1, 2, 3) if i < 10) yield i + 1
* res1: List[Int] = List(2, 3, 4)
*
* scala> for {
* | i <- Chain(1, 2, 3)
* | j <- Chain('a', 'b', 'c')
* | } yield (i, j)
* res3: org.scalactic.Chain[(Int, Char)] =
* Chain((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))
*
* scala> for {
* | i <- Chain(1, 2, 3) if i < 10
* | j <- Chain('a', 'b', 'c')
* | } yield (i, j)
* res6: List[(Int, Char)] =
* List((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))
*
*
* @tparam T the type of elements contained in this Chain
*/
final class Chain[+T] private (val toList: List[T]) extends AnyVal {
/**
* Returns a new Chain containing the elements of this Chain followed by the elements of the passed Chain.
* The element type of the resulting Chain is the most specific superclass encompassing the element types of this and the passed Chain.
*
* @tparam U the element type of the returned Chain
* @param other the Chain to append
* @return a new Chain that contains all the elements of this Chain followed by all elements of other.
*/
def ++[U >: T](other: Chain[U]): Chain[U] = new Chain(toList ++ other.toList)
/**
* Returns a new Chain containing the elements of this Chain followed by the elements of the passed Every.
* The element type of the resulting Chain is the most specific superclass encompassing the element types of this Chain and the passed Every.
*
* @tparam U the element type of the returned Chain
* @param other the Every to append
* @return a new Chain that contains all the elements of this Chain followed by all elements of other.
*/
def ++[U >: T](other: Every[U]): Chain[U] = new Chain(toList ++ other.toVector)
// TODO: Have I added these extra ++, etc. methods to Every that take a Chain?
/**
* Returns a new Chain containing the elements of this Chain followed by the elements of the passed GenTraversableOnce.
* The element type of the resulting Chain is the most specific superclass encompassing the element types of this Chain
* and the passed GenTraversableOnce.
*
* @tparam U the element type of the returned Chain
* @param other the GenTraversableOnce to append
* @return a new Chain that contains all the elements of this Chain followed by all elements of other.
*/
def ++[U >: T](other: GenTraversableOnce[U]): Chain[U] =
if (other.isEmpty) this else new Chain(toList ++ other)
/**
* Fold left: applies a binary operator to a start value, z, and all elements of this Chain, going left to right.
*
*
* Note: /: is alternate syntax for the foldLeft method; z /: chain is the
* same as chain foldLeft z.
*
*
* @tparam B the result of the binary operator
* @param z the start value
* @param op the binary operator
* @return the result of inserting op between consecutive elements of this Chain, going left to right, with the start value,
* z, on the left:
*
*
* op(...op(op(z, x_1), x_2), ..., x_n)
*
*
*
* where x1, ..., xn are the elements of this Chain.
*
*/
final def /:[B](z: B)(op: (B, T) => B): B = toList./:(z)(op)
/**
* Fold right: applies a binary operator to all elements of this Chain and a start value, going right to left.
*
*
* Note: :\ is alternate syntax for the foldRight method; chain :\ z is the same
* as chain foldRight z.
*
*
* @tparam B the result of the binary operator
* @param z the start value
* @param op the binary operator
* @return the result of inserting op between consecutive elements of this Chain, going right to left, with the start value,
* z, on the right:
*
*
* op(x_1, op(x_2, ... op(x_n, z)...))
*
*
*
* where x1, ..., xn are the elements of this Chain.
*
*/
final def :\[B](z: B)(op: (T, B) => B): B = toList.:\(z)(op)
/**
* Returns a new Chain with the given element prepended.
*
*
* Note that :-ending operators are right associative. A mnemonic for +: vs. :+ is: the COLon goes on the COLlection side.
*
*
* @param element the element to prepend to this Chain
* @return a new Chain consisting of element followed by all elements of this Chain.
*/
final def +:[U >: T](element: U): Chain[U] = new Chain(element +: toList)
/**
* Adds an element to the beginning of this Chain.
*
*
* Note that :-ending operators are right associative. A mnemonic for +: vs. :+ is: the COLon goes on the COLlection side.
*
*
* @param element the element to prepend to this Chain
* @return a Chain that contains element as first element and that continues with this Chain.
*/
final def ::[U >: T](element: U): Chain[U] = new Chain(element +: toList)
/**
* Returns a new Chain containing the elements of this Chain followed by the elements of the passed Chain.
* The element type of the resulting Chain is the most specific superclass encompassing the element types of this and the passed Chain.
*
* @tparam U the element type of the returned Chain
* @param other the Chain to append
* @return a new Chain that contains all the elements of this Chain followed by all elements of other.
*/
def :::[U >: T](other: Chain[U]): Chain[U] = new Chain(other.toList ::: toList)
/**
* Returns a new Chain containing the elements of this Chain followed by the elements of the passed Every.
* The element type of the resulting Chain is the most specific superclass encompassing the element types of this and the passed Every.
*
* @tparam U the element type of the returned Chain
* @param other the Every to append
* @return a new Chain that contains all the elements of this Chain followed by all elements of other.
*/
def :::[U >: T](other: Every[U]): Chain[U] = new Chain(other.toList ::: toList)
/**
* Returns a new Chain containing the elements of this Chain followed by the elements of the passed GenTraversableOnce.
* The element type of the resulting Chain is the most specific superclass encompassing the element types of this Chain
* and the passed GenTraversableOnce.
*
* @tparam U the element type of the returned Chain
* @param other the GenTraversableOnce to append
* @return a new Chain that contains all the elements of this Chain followed by all elements of other.
*/
def :::[U >: T](other: GenTraversableOnce[U]): Chain[U] =
if (other.isEmpty) this else new Chain(other.toList ::: toList)
/**
* Returns a new Chain with the given element appended.
*
*
* Note a mnemonic for +: vs. :+ is: the COLon goes on the COLlection side.
*
*
* @param element the element to append to this Chain
* @return a new Chain consisting of all elements of this Chain followed by element.
*/
def :+[U >: T](element: U): Chain[U] = new Chain(toList :+ element)
/**
* Appends all elements of this Chain to a string builder. The written text will consist of a concatenation of the result of invoking toString
* on of every element of this Chain, without any separator string.
*
* @param sb the string builder to which elements will be appended
* @return the string builder, sb, to which elements were appended.
*/
final def addString(sb: StringBuilder): StringBuilder = toList.addString(sb)
/**
* Appends all elements of this Chain to a string builder using a separator string. The written text will consist of a concatenation of the
* result of invoking toString
* on of every element of this Chain, separated by the string sep.
*
* @param sb the string builder to which elements will be appended
* @param sep the separator string
* @return the string builder, sb, to which elements were appended.
*/
final def addString(sb: StringBuilder, sep: String): StringBuilder = toList.addString(sb, sep)
/**
* Appends all elements of this Chain to a string builder using start, end, and separator strings. The written text will consist of a concatenation of
* the string start; the result of invoking toString on all elements of this Chain,
* separated by the string sep; and the string end
*
* @param sb the string builder to which elements will be appended
* @param start the starting string
* @param sep the separator string
* @param start the ending string
* @return the string builder, sb, to which elements were appended.
*/
final def addString(sb: StringBuilder, start: String, sep: String, end: String): StringBuilder = toList.addString(sb, start, sep, end)
/**
* Selects an element by its index in the Chain.
*
* @return the element of this Chain at index idx, where 0 indicates the first element.
*/
final def apply(idx: Int): T = toList(idx)
/**
* Finds the first element of this Chain for which the given partial function is defined, if any, and applies the partial function to it.
*
* @param pf the partial function
* @return an Option containing pf applied to the first element for which it is defined, or None if
* the partial function was not defined for any element.
*/
final def collectFirst[U](pf: PartialFunction[T, U]): Option[U] = toList.collectFirst(pf)
/**
* Indicates whether this Chain contains a given value as an element.
*
* @param elem the element to look for
* @return true if this Chain has an element that is equal (as determined by ==) to elem, false otherwise.
*/
final def contains(elem: Any): Boolean = toList.contains(elem)
/**
* Indicates whether this Chain contains a given GenSeq as a slice.
*
* @param that the GenSeq slice to look for
* @return true if this Chain contains a slice with the same elements as that, otherwise false.
*/
final def containsSlice[B](that: GenSeq[B]): Boolean = toList.containsSlice(that)
/**
* Indicates whether this Chain contains a given Every as a slice.
*
* @param that the Every slice to look for
* @return true if this Chain contains a slice with the same elements as that, otherwise false.
*/
final def containsSlice[B](that: Every[B]): Boolean = toList.containsSlice(that.toVector)
/**
* Indicates whether this Chain contains a given Chain as a slice.
*
* @param that the Chain slice to look for
* @return true if this Chain contains a slice with the same elements as that, otherwise false.
*/
final def containsSlice[B](that: Chain[B]): Boolean = toList.containsSlice(that.toList)
/**
* Copies values of this Chain to an array. Fills the given array arr with values of this Chain. Copying
* will stop once either the end of the current Chain is reached, or the end of the array is reached.
*
* @param arr the array to fill
*/
final def copyToArray[U >: T](arr: Array[U]): Unit = toList.copyToArray(arr)
/**
* Copies values of this Chain to an array. Fills the given array arr with values of this Chain, beginning at
* index start. Copying will stop once either the end of the current Chain is reached, or the end of the array is reached.
*
* @param arr the array to fill
* @param start the starting index
*/
final def copyToArray[U >: T](arr: Array[U], start: Int): Unit = toList.copyToArray(arr, start)
/**
* Copies values of this Chain to an array. Fills the given array arr with at most len elements of this Chain, beginning at
* index start. Copying will stop once either the end of the current Chain is reached, the end of the array is reached, or
* len elements have been copied.
*
* @param arr the array to fill
* @param start the starting index
* @param len the maximum number of elements to copy
*/
final def copyToArray[U >: T](arr: Array[U], start: Int, len: Int): Unit = toList.copyToArray(arr, start, len)
/**
* Copies all elements of this Chain to a buffer.
*
* @param buf the buffer to which elements are copied
*/
final def copyToBuffer[U >: T](buf: Buffer[U]): Unit = toList.copyToBuffer(buf)
/**
* Indicates whether every element of this Chain relates to the corresponding element of a given GenSeq by satisfying a given predicate.
*
* @tparam B the type of the elements of that
* @param that the GenSeq to compare for correspondence
* @param p the predicate, which relates elements from this Chain and the passed GenSeq
* @return true if this Chain and the passed GenSeq have the same length and p(x, y) is true
* for all corresponding elements x of this Chain and y of that, otherwise false.
*/
final def corresponds[B](that: GenSeq[B])(p: (T, B) => Boolean): Boolean = toList.corresponds(that)(p)
/**
* Indicates whether every element of this Chain relates to the corresponding element of a given Every by satisfying a given predicate.
*
* @tparam B the type of the elements of that
* @param that the Every to compare for correspondence
* @param p the predicate, which relates elements from this Chain and the passed Every
* @return true if this Chain and the passed Every have the same length and p(x, y) is true
* for all corresponding elements x of this Chain and y of that, otherwise false.
*/
final def corresponds[B](that: Every[B])(p: (T, B) => Boolean): Boolean = toList.corresponds(that.toVector)(p)
/**
* Indicates whether every element of this Chain relates to the corresponding element of a given Chain by satisfying a given predicate.
*
* @tparam B the type of the elements of that
* @param that the Chain to compare for correspondence
* @param p the predicate, which relates elements from this and the passed Chain
* @return true if this and the passed Chain have the same length and p(x, y) is true
* for all corresponding elements x of this Chain and y of that, otherwise false.
*/
final def corresponds[B](that: Chain[B])(p: (T, B) => Boolean): Boolean = toList.corresponds(that.toList)(p)
/**
* Counts the number of elements in this Chain that satisfy a predicate.
*
* @param p the predicate used to test elements.
* @return the number of elements satisfying the predicate p.
*/
final def count(p: T => Boolean): Int = toList.count(p)
/**
* Builds a new Chain from this Chain without any duplicate elements.
*
* @return A new Chain that contains the first occurrence of every element of this Chain.
*/
final def distinct: Chain[T] = new Chain(toList.distinct)
/**
* Indicates whether this Chain ends with the given GenSeq.
*
* @param that the sequence to test
* @return true if this Chain has that as a suffix, false otherwise.
*/
final def endsWith[B](that: GenSeq[B]): Boolean = toList.endsWith(that)
/**
* Indicates whether this Chain ends with the given Every.
*
* @param that the Every to test
* @return true if this Chain has that as a suffix, false otherwise.
*/
final def endsWith[B](that: Every[B]): Boolean = toList.endsWith(that.toVector)
// TODO: Search for that: Every in here and add a that: Chain in Every.
/**
* Indicates whether this Chain ends with the given Chain.
*
* @param that the Chain to test
* @return true if this Chain has that as a suffix, false otherwise.
*/
final def endsWith[B](that: Chain[B]): Boolean = toList.endsWith(that.toList)
/*
override def equals(o: Any): Boolean =
o match {
case chain: Chain[_] => toList == chain.toList
case _ => false
}
*/
/**
* Indicates whether a predicate holds for at least one of the elements of this Chain.
*
* @param the predicate used to test elements.
* @return true if the given predicate p holds for some of the elements of this Chain, otherwise false.
*/
final def exists(p: T => Boolean): Boolean = toList.exists(p)
/**
* Finds the first element of this Chain that satisfies the given predicate, if any.
*
* @param p the predicate used to test elements
* @return an Some containing the first element in this Chain that satisfies p, or None if none exists.
*/
final def find(p: T => Boolean): Option[T] = toList.find(p)
/**
* Builds a new Chain by applying a function to all elements of this Chain and using the elements of the resulting Chains.
*
* @tparam U the element type of the returned Chain
* @param f the function to apply to each element.
* @return a new Chain containing elements obtained by applying the given function f to each element of this Chain and concatenating
* the elements of resulting Chains.
*/
final def flatMap[U](f: T => Chain[U]): Chain[U] = {
val buf = new ArrayBuffer[U]
for (ele <- toList)
buf ++= f(ele).toList
new Chain(buf.toList)
}
/**
* Converts this Chain of Chains into a Chain
* formed by the elements of the nested Chains.
*
*
* Note: You cannot use this flatten method on a Chain that contains a GenTraversableOnces, because
* if all the nested GenTraversableOnces were empty, you'd end up with an empty Chain.
*
*
* @tparm B the type of the elements of each nested Chain
* @return a new Chain resulting from concatenating all nested Chains.
*/
final def flatten[B](implicit ev: T <:< Chain[B]): Chain[B] = flatMap(ev)
/**
* Folds the elements of this Chain using the specified associative binary operator.
*
*
* The order in which operations are performed on elements is unspecified and may be nondeterministic.
*
*
* @tparam U a type parameter for the binary operator, a supertype of T.
* @param z a neutral element for the fold operation; may be added to the result an arbitrary number of
* times, and must not change the result (e.g., Nil for list concatenation,
* 0 for addition, or 1 for multiplication.)
* @param op a binary operator that must be associative
* @return the result of applying fold operator op between all the elements and z
*/
final def fold[U >: T](z: U)(op: (U, U) => U): U = toList.fold(z)(op)
/**
* Applies a binary operator to a start value and all elements of this Chain, going left to right.
*
* @tparam B the result type of the binary operator.
* @param z the start value.
* @param op the binary operator.
* @return the result of inserting op between consecutive elements of this Chain, going left to right, with the start value,
* z, on the left:
*
*
* op(...op(op(z, x_1), x_2), ..., x_n)
*
*
*
* where x1, ..., xn are the elements of this Chain.
*
*/
final def foldLeft[B](z: B)(op: (B, T) => B): B = toList.foldLeft(z)(op)
/**
* Applies a binary operator to all elements of this Chain and a start value, going right to left.
*
* @tparam B the result of the binary operator
* @param z the start value
* @param op the binary operator
* @return the result of inserting op between consecutive elements of this Chain, going right to left, with the start value,
* z, on the right:
*
*
* op(x_1, op(x_2, ... op(x_n, z)...))
*
*
*
* where x1, ..., xn are the elements of this Chain.
*
*/
final def foldRight[B](z: B)(op: (T, B) => B): B = toList.foldRight(z)(op)
/**
* Indicates whether a predicate holds for all elements of this Chain.
*
* @param p the predicate used to test elements.
* @return true if the given predicate p holds for all elements of this Chain, otherwise false.
*/
final def forall(p: T => Boolean): Boolean = toList.forall(p)
/**
* Applies a function f to all elements of this Chain.
*
* @param f the function that is applied for its side-effect to every element. The result of function f is discarded.
*/
final def foreach(f: T => Unit): Unit = toList.foreach(f)
/**
* Partitions this Chain into a map of Chains according to some discriminator function.
*
* @tparam K the type of keys returned by the discriminator function.
* @param f the discriminator function.
* @return A map from keys to Chains such that the following invariant holds:
*
*
* (chain.toList partition f)(k) = xs filter (x => f(x) == k)
*
*
*
* That is, every key k is bound to a Chain of those elements x for which f(x) equals k.
*
*/
final def groupBy[K](f: T => K): Map[K, Chain[T]] = {
val mapKToList = toList.groupBy(f)
mapKToList.mapValues { list => new Chain(list) }
}
/**
* Partitions elements into fixed size Chains.
*
* @param size the number of elements per group
* @return An iterator producing Chains of size size, except the last will be truncated if the elements don't divide evenly.
*/
final def grouped(size: Int): Iterator[Chain[T]] = {
val itOfList = toList.grouped(size)
itOfList.map { list => new Chain(list) }
}
/**
* Returns true to indicate this Chain has a definite size, since all Chains are strict collections.
*/
final def hasDefiniteSize: Boolean = true
// override def hashCode: Int = toList.hashCode
/**
* Selects the first element of this Chain.
*
* @return the first element of this Chain.
*/
final def head: T = toList.head
// Methods like headOption I can't get rid of because of the implicit conversion to GenTraversable.
// Users can call any of the methods I've left out on a Chain, and get whatever List would return
// for that method call. Eventually I'll probably implement them all to save the implicit conversion.
/**
* Selects the first element of this Chain and returns it wrapped in a Some.
*
* @return the first element of this Chain, wrapped in a Some.
*/
final def headOption: Option[T] = toList.headOption
/**
* Finds index of first occurrence of some value in this Chain.
*
* @param elem the element value to search for.
* @return the index of the first element of this Chain that is equal (as determined by ==) to elem,
* or -1, if none exists.
*/
final def indexOf[U >: T](elem: U): Int = toList.indexOf(elem, 0)
/**
* Finds index of first occurrence of some value in this Chain after or at some start index.
*
* @param elem the element value to search for.
* @param from the start index
* @return the index >= from of the first element of this Chain that is equal (as determined by ==) to elem,
* or -1, if none exists.
*/
final def indexOf[U >: T](elem: U, from: Int): Int = toList.indexOf(elem, from)
/**
* Finds first index where this Chain contains a given GenSeq as a slice.
*
* @param that the GenSeq defining the slice to look for
* @return the first index at which the elements of this Chain starting at that index match the elements of
* GenSeq that, or -1 of no such subsequence exists.
*/
final def indexOfSlice[U >: T](that: GenSeq[U]): Int = toList.indexOfSlice(that)
/**
* Finds first index after or at a start index where this Chain contains a given GenSeq as a slice.
*
* @param that the GenSeq defining the slice to look for
* @param from the start index
* @return the first index >= from at which the elements of this Chain starting at that index match the elements of
* GenSeq that, or -1 of no such subsequence exists.
*/
final def indexOfSlice[U >: T](that: GenSeq[U], from: Int): Int = toList.indexOfSlice(that, from)
/**
* Finds first index where this Chain contains a given Every as a slice.
*
* @param that the Every defining the slice to look for
* @return the first index such that the elements of this Chain starting at this index match the elements of
* Every that, or -1 of no such subsequence exists.
*/
final def indexOfSlice[U >: T](that: Every[U]): Int = toList.indexOfSlice(that.toVector)
/**
* Finds first index where this Chain contains a given Chain as a slice.
*
* @param that the Chain defining the slice to look for
* @return the first index such that the elements of this Chain starting at this index match the elements of
* Chain that, or -1 of no such subsequence exists.
*/
final def indexOfSlice[U >: T](that: Chain[U]): Int = toList.indexOfSlice(that.toList)
/**
* Finds first index after or at a start index where this Chain contains a given Every as a slice.
*
* @param that the Every defining the slice to look for
* @param from the start index
* @return the first index >= from such that the elements of this Chain starting at this index match the elements of
* Every that, or -1 of no such subsequence exists.
*/
final def indexOfSlice[U >: T](that: Every[U], from: Int): Int = toList.indexOfSlice(that.toVector, from)
/**
* Finds first index after or at a start index where this Chain contains a given Chain as a slice.
*
* @param that the Chain defining the slice to look for
* @param from the start index
* @return the first index >= from such that the elements of this Chain starting at this index match the elements of
* Chain that, or -1 of no such subsequence exists.
*/
final def indexOfSlice[U >: T](that: Chain[U], from: Int): Int = toList.indexOfSlice(that.toList, from)
/**
* Finds index of the first element satisfying some predicate.
*
* @param p the predicate used to test elements.
* @return the index of the first element of this Chain that satisfies the predicate p,
* or -1, if none exists.
*/
final def indexWhere(p: T => Boolean): Int = toList.indexWhere(p)
/**
* Finds index of the first element satisfying some predicate after or at some start index.
*
* @param p the predicate used to test elements.
* @param from the start index
* @return the index >= from of the first element of this Chain that satisfies the predicate p,
* or -1, if none exists.
*/
final def indexWhere(p: T => Boolean, from: Int): Int = toList.indexWhere(p, from)
/**
* Produces the range of all indices of this Chain.
*
* @return a Range value from 0 to one less than the length of this Chain.
*/
final def indices: Range = toList.indices
/**
* Tests whether this Chain contains given index.
*
* @param idx the index to test
* @return true if this Chain contains an element at position idx, false otherwise.
*/
final def isDefinedAt(idx: Int): Boolean = toList.isDefinedAt(idx)
/**
* Returns false to indicate this Chain, like all Chains, is non-empty.
*
* @return false
*/
final def isEmpty: Boolean = false
/**
* Returns true to indicate this Chain, like all Chains, can be traversed repeatedly.
*
* @return true
*/
final def isTraversableAgain: Boolean = true
/**
* Creates and returns a new iterator over all elements contained in this Chain.
*
* @return the new iterator
*/
final def iterator: Iterator[T] = toList.iterator
/**
* Selects the last element of this Chain.
*
* @return the last element of this Chain.
*/
final def last: T = toList.last
/**
* Finds the index of the last occurrence of some value in this Chain.
*
* @param elem the element value to search for.
* @return the index of the last element of this Chain that is equal (as determined by ==) to elem,
* or -1, if none exists.
*/
final def lastIndexOf[U >: T](elem: U): Int = toList.lastIndexOf(elem)
/**
* Finds the index of the last occurrence of some value in this Chain before or at a given end index.
*
* @param elem the element value to search for.
* @param end the end index.
* @return the index >= end of the last element of this Chain that is equal (as determined by ==)
* to elem, or -1, if none exists.
*/
final def lastIndexOf[U >: T](elem: U, end: Int): Int = toList.lastIndexOf(elem, end)
/**
* Finds the last index where this Chain contains a given GenSeq as a slice.
*
* @param that the GenSeq defining the slice to look for
* @return the last index at which the elements of this Chain starting at that index match the elements of
* GenSeq that, or -1 of no such subsequence exists.
*/
final def lastIndexOfSlice[U >: T](that: GenSeq[U]): Int = toList.lastIndexOfSlice(that)
/**
* Finds the last index before or at a given end index where this Chain contains a given GenSeq as a slice.
*
* @param that the GenSeq defining the slice to look for
* @param end the end index
* @return the last index >= end at which the elements of this Chain starting at that index match the elements of
* GenSeq that, or -1 of no such subsequence exists.
*/
final def lastIndexOfSlice[U >: T](that: GenSeq[U], end: Int): Int = toList.lastIndexOfSlice(that, end)
/**
* Finds the last index where this Chain contains a given Every as a slice.
*
* @param that the Every defining the slice to look for
* @return the last index at which the elements of this Chain starting at that index match the elements of
* Every that, or -1 of no such subsequence exists.
*/
final def lastIndexOfSlice[U >: T](that: Every[U]): Int = toList.lastIndexOfSlice(that.toVector)
/**
* Finds the last index where this Chain contains a given Chain as a slice.
*
* @param that the Chain defining the slice to look for
* @return the last index at which the elements of this Chain starting at that index match the elements of
* Chain that, or -1 of no such subsequence exists.
*/
final def lastIndexOfSlice[U >: T](that: Chain[U]): Int = toList.lastIndexOfSlice(that.toList)
/**
* Finds the last index before or at a given end index where this Chain contains a given Every as a slice.
*
* @param that the Every defining the slice to look for
* @param end the end index
* @return the last index >= end at which the elements of this Chain starting at that index match the elements of
* Every that, or -1 of no such subsequence exists.
*/
final def lastIndexOfSlice[U >: T](that: Every[U], end: Int): Int = toList.lastIndexOfSlice(that.toVector, end)
/**
* Finds the last index before or at a given end index where this Chain contains a given Chain as a slice.
*
* @param that the Chain defining the slice to look for
* @param end the end index
* @return the last index >= end at which the elements of this Chain starting at that index match the elements of
* Chain that, or -1 of no such subsequence exists.
*/
final def lastIndexOfSlice[U >: T](that: Chain[U], end: Int): Int = toList.lastIndexOfSlice(that.toList, end)
/**
* Finds index of last element satisfying some predicate.
*
* @param p the predicate used to test elements.
* @return the index of the last element of this Chain that satisfies the predicate p, or -1, if none exists.
*/
final def lastIndexWhere(p: T => Boolean): Int = toList.lastIndexWhere(p)
/**
* Finds index of last element satisfying some predicate before or at given end index.
*
* @param p the predicate used to test elements.
* @param end the end index
* @return the index >= end of the last element of this Chain that satisfies the predicate p,
* or -1, if none exists.
*/
final def lastIndexWhere(p: T => Boolean, end: Int): Int = toList.lastIndexWhere(p, end)
/**
* Returns the last element of this Chain, wrapped in a Some.
*
* @return the last element, wrapped in a Some.
*/
final def lastOption: Option[T] = toList.lastOption // Will always return a Some
/**
* The length of this Chain.
*
*
* Note: length and size yield the same result, which will be >= 1.
*
*
* @return the number of elements in this Chain.
*/
final def length: Int = toList.length
/**
* Compares the length of this Chain 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
*
*/
final def lengthCompare(len: Int): Int = toList.lengthCompare(len)
/**
* Builds a new Chain by applying a function to all elements of this Chain.
*
* @tparam U the element type of the returned Chain.
* @param f the function to apply to each element.
* @return a new Chain resulting from applying the given function f to each element of this Chain and collecting the results.
*/
final def map[U](f: T => U): Chain[U] =
new Chain(toList.map(f))
/**
* Finds the largest element.
*
* @return the largest element of this Chain.
*/
final def max[U >: T](implicit cmp: Ordering[U]): T = toList.max(cmp)
/**
* Finds the largest result after applying the given function to every element.
*
* @return the largest result of applying the given function to every element of this Chain.
*/
final def maxBy[U](f: T => U)(implicit cmp: Ordering[U]): T = toList.maxBy(f)(cmp)
/**
* Finds the smallest element.
*
* @return the smallest element of this Chain.
*/
final def min[U >: T](implicit cmp: Ordering[U]): T = toList.min(cmp)
/**
* Finds the smallest result after applying the given function to every element.
*
* @return the smallest result of applying the given function to every element of this Chain.
*/
final def minBy[U](f: T => U)(implicit cmp: Ordering[U]): T = toList.minBy(f)(cmp)
/**
* Displays all elements of this Chain in a string.
*
* @return a string representation of this Chain. In the resulting string, the result of invoking toString on all elements of this
* Chain follow each other without any separator string.
*/
final def mkString: String = toList.mkString
/**
* Displays all elements of this Chain in a string using a separator string.
*
* @param sep the separator string
* @return a string representation of this Chain. In the resulting string, the result of invoking toString on all elements of this
* Chain are separated by the string sep.
*/
final def mkString(sep: String): String = toList.mkString(sep)
/**
* Displays all elements of this Chain in a string using start, end, and separator strings.
*
* @param start the starting string.
* @param sep the separator string.
* @param end the ending string.
* @return a string representation of this Chain. The resulting string begins with the string start and ends with the string
* end. Inside, In the resulting string, the result of invoking toString on all elements of this Chain are
* separated by the string sep.
*/
final def mkString(start: String, sep: String, end: String): String = toList.mkString(start, sep, end)
/**
* Returns true to indicate this Chain, like all Chains, is non-empty.
*
* @return true
*/
final def nonEmpty: Boolean = true
/**
* A copy of this Chain with an element value appended until a given target length is reached.
*
* @param len the target length
* @param elem he padding value
* @return a new Chain consisting of all elements of this Chain followed by the minimal number of occurrences
* of elem so that the resulting Chain has a length of at least len.
*/
final def padTo[U >: T](len: Int, elem: U): Chain[U] =
new Chain(toList.padTo(len, elem))
/**
* Produces a new Chain where a slice of elements in this Chain is replaced by another Chain
*
* @param from the index of the first replaced element
* @param that the Chain whose elements should replace a slice in this Chain
* @param replaced the number of elements to drop in the original Chain
*/
final def patch[U >: T](from: Int, that: Chain[U], replaced: Int): Chain[U] =
new Chain(toList.patch(from, that.toVector, replaced))
/**
* Iterates over distinct permutations.
*
*
* Here's an example:
*
*
*
* Chain('a', 'b', 'b').permutations.toList = List(Chain(a, b, b), Chain(b, a, b), Chain(b, b, a))
*
*
* @return an iterator that traverses the distinct permutations of this Chain.
*/
final def permutations: Iterator[Chain[T]] = {
val it = toList.permutations
it map { list => new Chain(list) }
}
/**
* Returns the length of the longest prefix whose elements all satisfy some predicate.
*
* @param p the predicate used to test elements.
* @return the length of the longest prefix of this Chain such that every element
* of the segment satisfies the predicate p.
*/
final def prefixLength(p: T => Boolean): Int = toList.prefixLength(p)
/**
* The result of multiplying all the elements of this Chain.
*
*
* This method can be invoked for any Chain[T] for which an implicit Numeric[T] exists.
*
*
* @return the product of all elements
*/
final def product[U >: T](implicit num: Numeric[U]): U = toList.product(num)
/**
* Reduces the elements of this Chain using the specified associative binary operator.
*
*
* The order in which operations are performed on elements is unspecified and may be nondeterministic.
*
*
* @tparam U a type parameter for the binary operator, a supertype of T.
* @param op a binary operator that must be associative.
* @return the result of applying reduce operator op between all the elements of this Chain.
*/
final def reduce[U >: T](op: (U, U) => U): U = toList.reduce(op)
/**
* Applies a binary operator to all elements of this Chain, going left to right.
*
* @tparam U the result type of the binary operator.
* @param op the binary operator.
* @return the result of inserting op between consecutive elements of this Chain, going left to right:
*
*
* op(...op(op(x_1, x_2), x_3), ..., x_n)
*
*
*
* where x1, ..., xn are the elements of this Chain.
*
*/
final def reduceLeft[U >: T](op: (U, T) => U): U = toList.reduceLeft(op)
/**
* Applies a binary operator to all elements of this Chain, going left to right, returning the result in a Some.
*
* @tparam U the result type of the binary operator.
* @param op the binary operator.
* @return a Some containing the result of reduceLeft(op)
*
*/
final def reduceLeftOption[U >: T](op: (U, T) => U): Option[U] = toList.reduceLeftOption(op)
final def reduceOption[U >: T](op: (U, U) => U): Option[U] = toList.reduceOption(op)
/**
* Applies a binary operator to all elements of this Chain, going right to left.
*
* @tparam U the result of the binary operator
* @param op the binary operator
* @return the result of inserting op between consecutive elements of this Chain, going right to left:
*
*
* op(x_1, op(x_2, ... op(x_{n-1}, x_n)...))
*
*
*
* where x1, ..., xn are the elements of this Chain.
*
*/
final def reduceRight[U >: T](op: (T, U) => U): U = toList.reduceRight(op)
/**
* Applies a binary operator to all elements of this Chain, going right to left, returning the result in a Some.
*
* @tparam U the result of the binary operator
* @param op the binary operator
* @return a Some containing the result of reduceRight(op)
*/
final def reduceRightOption[U >: T](op: (T, U) => U): Option[U] = toList.reduceRightOption(op)
/**
* Returns new Chain with elements in reverse order.
*
* @return a new Chain with all elements of this Chain in reversed order.
*/
final def reverse: Chain[T] =
new Chain(toList.reverse)
/**
* An iterator yielding elements in reverse order.
*
*
* Note: chain.reverseIterator is the same as chain.reverse.iterator, but might be more efficient.
*
*
* @return an iterator yielding the elements of this Chain in reversed order
*/
final def reverseIterator: Iterator[T] = toList.reverseIterator
/**
* Builds a new Chain by applying a function to all elements of this Chain and collecting the results in reverse order.
*
*
* Note: chain.reverseMap(f) is the same as chain.reverse.map(f), but might be more efficient.
*
*
* @tparam U the element type of the returned Chain.
* @param f the function to apply to each element.
* @return a new Chain resulting from applying the given function f to each element of this Chain
* and collecting the results in reverse order.
*/
final def reverseMap[U](f: T => U): Chain[U] =
new Chain(toList.reverseMap(f))
/**
* Checks if the given GenIterable contains the same elements in the same order as this Chain.
*
* @param that the GenIterable with which to compare
* @return true, if both this Chain and the given GenIterable contain the same elements
* in the same order, false otherwise.
*/
final def sameElements[U >: T](that: GenIterable[U]): Boolean = toList.sameElements(that)
/**
* Checks if the given Every contains the same elements in the same order as this Chain.
*
* @param that the Every with which to compare
* @return true, if both this and the given Every contain the same elements
* in the same order, false otherwise.
*/
final def sameElements[U >: T](that: Every[U]): Boolean = toList.sameElements(that.toVector)
/**
* Checks if the given Chain contains the same elements in the same order as this Chain.
*
* @param that the Chain with which to compare
* @return true, if both this and the given Chain contain the same elements
* in the same order, false otherwise.
*/
final def sameElements[U >: T](that: Chain[U]): Boolean = toList.sameElements(that.toList)
/**
* Computes a prefix scan of the elements of this Chain.
*
*
* Note: The neutral element z may be applied more than once.
*
*
*
* Here are some examples:
*
*
*
* Chain(1, 2, 3).scan(0)(_ + _) == Chain(0, 1, 3, 6)
* Chain(1, 2, 3).scan("z")(_ + _.toString) == Chain("z", "z1", "z12", "z123")
*
*
* @tparam U a type parameter for the binary operator, a supertype of T, and the type of the resulting Chain.
* @param z a neutral element for the scan operation; may be added to the result an arbitrary number of
* times, and must not change the result (e.g., Nil for list concatenation,
* 0 for addition, or 1 for multiplication.)
* @param op a binary operator that must be associative
* @return a new Chain containing the prefix scan of the elements in this Chain
*/
final def scan[U >: T](z: U)(op: (U, U) => U): Chain[U] = new Chain(toList.scan(z)(op))
/**
* Produces a Chain containing cumulative results of applying the operator going left to right.
*
*
* Here are some examples:
*
*
*
* Chain(1, 2, 3).scanLeft(0)(_ + _) == Chain(0, 1, 3, 6)
* Chain(1, 2, 3).scanLeft("z")(_ + _) == Chain("z", "z1", "z12", "z123")
*
*
* @tparam B the result type of the binary operator and type of the resulting Chain
* @param z the start value.
* @param op the binary operator.
* @return a new Chain containing the intermediate results of inserting op between consecutive elements of this Chain,
* going left to right, with the start value, z, on the left.
*/
final def scanLeft[B](z: B)(op: (B, T) => B): Chain[B] = new Chain(toList.scanLeft(z)(op))
/**
* Produces a Chain containing cumulative results of applying the operator going right to left.
*
*
* Here are some examples:
*
*
*
* Chain(1, 2, 3).scanRight(0)(_ + _) == Chain(6, 5, 3, 0)
* Chain(1, 2, 3).scanRight("z")(_ + _) == Chain("123z", "23z", "3z", "z")
*
*
* @tparam B the result of the binary operator and type of the resulting Chain
* @param z the start value
* @param op the binary operator
* @return a new Chain containing the intermediate results of inserting op between consecutive elements of this Chain,
* going right to left, with the start value, z, on the right.
*/
final def scanRight[B](z: B)(op: (T, B) => B): Chain[B] = new Chain(toList.scanRight(z)(op))
/**
* Computes length of longest segment whose elements all satisfy some predicate.
*
* @param p the predicate used to test elements.
* @param from the index where the search starts.
* @param the length of the longest segment of this Chain starting from index from such that every element of the
* segment satisfies the predicate p.
*/
final def segmentLength(p: T => Boolean, from: Int): Int = toList.segmentLength(p, from)
/**
* Groups elements in fixed size blocks by passing a “sliding window” over them (as opposed to partitioning them, as is done in grouped.)
*
* @param size the number of elements per group
* @return an iterator producing Chains of size size, except the last and the only element will be truncated
* if there are fewer elements than size.
*/
final def sliding(size: Int): Iterator[Chain[T]] = toList.sliding(size).map(new Chain(_))
/**
* Groups elements in fixed size blocks by passing a “sliding window” over them (as opposed to partitioning them, as is done in grouped.),
* moving the sliding window by a given step each time.
*
* @param size the number of elements per group
* @param step the distance between the first elements of successive groups
* @return an iterator producing Chains of size size, except the last and the only element will be truncated
* if there are fewer elements than size.
*/
final def sliding(size: Int, step: Int): Iterator[Chain[T]] = toList.sliding(size, step).map(new Chain(_))
/**
* The size of this Chain.
*
*
* Note: length and size yield the same result, which will be >= 1.
*
*
* @return the number of elements in this Chain.
*/
final def size: Int = toList.size
/**
* Sorts this Chain according to the Ordering of the result of applying the given function to every element.
*
* @tparam U the target type of the transformation f, and the type where the Ordering ord is defined.
* @param f the transformation function mapping elements to some other domain U.
* @param ord the ordering assumed on domain U.
* @return a Chain consisting of the elements of this Chain sorted according to the Ordering where
* x < y if ord.lt(f(x), f(y)).
*/
final def sortBy[U](f: T => U)(implicit ord: Ordering[U]): Chain[T] = new Chain(toList.sortBy(f))
/**
* Sorts this Chain according to a comparison function.
*
*
* The sort is stable. That is, elements that are equal (as determined by lt) appear in the same order in the
* sorted Chain as in the original.
*
*
* @param the comparison function that tests whether its first argument precedes its second argument in the desired ordering.
* @return a Chain consisting of the elements of this Chain sorted according to the comparison function lt.
*/
final def sortWith(lt: (T, T) => Boolean): Chain[T] = new Chain(toList.sortWith(lt))
/**
* Sorts this Chain according to an Ordering.
*
*
* The sort is stable. That is, elements that are equal (as determined by lt) appear in the same order in the
* sorted Chain as in the original.
*
*
* @param ord the Ordering to be used to compare elements.
* @param the comparison function that tests whether its first argument precedes its second argument in the desired ordering.
* @return a Chain consisting of the elements of this Chain sorted according to the comparison function lt.
*/
final def sorted[U >: T](implicit ord: Ordering[U]): Chain[U] = new Chain(toList.sorted(ord))
/**
* Indicates whether this Chain starts with the given GenSeq.
*
* @param that the GenSeq slice to look for in this Chain
* @return true if this Chain has that as a prefix, false otherwise.
*/
final def startsWith[B](that: GenSeq[B]): Boolean = toList.startsWith(that)
/**
* Indicates whether this Chain starts with the given GenSeq at the given index.
*
* @param that the GenSeq slice to look for in this Chain
* @param offset the index at which this Chain is searched.
* @return true if this Chain has that as a slice at the index offset, false otherwise.
*/
final def startsWith[B](that: GenSeq[B], offset: Int): Boolean = toList.startsWith(that, offset)
/**
* Indicates whether this Chain starts with the given Every.
*
* @param that the Every to test
* @return true if this collection has that as a prefix, false otherwise.
*/
final def startsWith[B](that: Every[B]): Boolean = toList.startsWith(that.toVector)
/**
* Indicates whether this Chain starts with the given Chain.
*
* @param that the Chain to test
* @return true if this collection has that as a prefix, false otherwise.
*/
final def startsWith[B](that: Chain[B]): Boolean = toList.startsWith(that.toList)
/**
* Indicates whether this Chain starts with the given Every at the given index.
*
* @param that the Every slice to look for in this Chain
* @param offset the index at which this Chain is searched.
* @return true if this Chain has that as a slice at the index offset, false otherwise.
*/
final def startsWith[B](that: Every[B], offset: Int): Boolean = toList.startsWith(that.toVector, offset)
/**
* Indicates whether this Chain starts with the given Chain at the given index.
*
* @param that the Chain slice to look for in this Chain
* @param offset the index at which this Chain is searched.
* @return true if this Chain has that as a slice at the index offset, false otherwise.
*/
final def startsWith[B](that: Chain[B], offset: Int): Boolean = toList.startsWith(that.toList, offset)
/**
* Returns "Chain", the prefix of this object's toString representation.
*
* @return the string "Chain"
*/
def stringPrefix: String = "Chain"
/**
* The result of summing all the elements of this Chain.
*
*
* This method can be invoked for any Chain[T] for which an implicit Numeric[T] exists.
*
*
* @return the sum of all elements
*/
final def sum[U >: T](implicit num: Numeric[U]): U = toList.sum(num)
import scala.language.higherKinds
/**
* Converts this Chain into a collection of type Col by copying all elements.
*
* @tparam Col the collection type to build.
* @return a new collection containing all elements of this Chain.
*/
final def to[Col[_]](implicit cbf: CanBuildFrom[Nothing, T, Col[T @uV]]): Col[T @uV] = toList.to[Col](cbf)
/**
* Converts this Chain to an array.
*
* @return an array containing all elements of this Chain. A ClassTag must be available for the element type of this Chain.
*/
final def toArray[U >: T](implicit classTag: ClassTag[U]): Array[U] = toList.toArray
/**
* Converts this Chain to a Vector.
*
* @return a Vector containing all elements of this Chain.
*/
final def toVector: Vector[T] = toList.toVector
/**
* Converts this Chain to a mutable buffer.
*
* @return a buffer containing all elements of this Chain.
*/
final def toBuffer[U >: T]: Buffer[U] = toList.toBuffer
/**
* Converts this Chain to an immutable IndexedSeq.
*
* @return an immutable IndexedSeq containing all elements of this Chain.
*/
final def toIndexedSeq: collection.immutable.IndexedSeq[T] = toList.toVector
/**
* Converts this Chain to an iterable collection.
*
* @return an Iterable containing all elements of this Chain.
*/
final def toIterable: Iterable[T] = toList.toIterable
/**
* Returns an Iterator over the elements in this Chain.
*
* @return an Iterator containing all elements of this Chain.
*/
final def toIterator: Iterator[T] = toList.toIterator
/**
* Converts this Chain to a list.
*
* @return a list containing all elements of this Chain.
*/
// final def toList: List[T] = toList
/**
* Converts this Chain to a map.
*
*
* This method is unavailable unless the elements are members of Tuple2, each ((K, V)) becoming a key-value pair
* in the map. Duplicate keys will be overwritten by later keys.
*
*
* @return a map of type immutable.Map[K, V] containing all key/value pairs of type (K, V) of this Chain.
*/
final def toMap[K, V](implicit ev: T <:< (K, V)): Map[K, V] = toList.toMap
/**
* Converts this Chain to an immutable IndexedSeq.
*
* @return an immutable IndexedSeq containing all elements of this Chain.
*/
final def toSeq: collection.immutable.Seq[T] = toList
/**
* Converts this Chain to a set.
*
* @return a set containing all elements of this Chain.
*/
final def toSet[U >: T]: Set[U] = toList.toSet
/**
* Converts this Chain to a stream.
*
* @return a stream containing all elements of this Chain.
*/
final def toStream: Stream[T] = toList.toStream
/**
* Returns a string representation of this Chain.
*
* @return the string "Chain" followed by the result of invoking toString on
* this Chain's elements, surrounded by parentheses.
*/
override def toString: String = "Chain(" + toList.mkString(", ") + ")"
/**
* Converts this Chain to an unspecified Traversable.
*
* @return a Traversable containing all elements of this Chain.
*/
final def toTraversable: Traversable[T] = toList.toTraversable
final def transpose[U](implicit ev: T <:< Chain[U]): Chain[Chain[U]] = {
val asLists = toList.map(ev)
val list = asLists.transpose
new Chain(list.map(new Chain(_)))
}
/**
* Produces a new Chain that contains all elements of this Chain and also all elements of a given Every.
*
*
* chainX union everyY is equivalent to chainX ++ everyY.
*
*
*
* Another way to express this is that chainX union everyY computes the order-presevring multi-set union
* of chainX and everyY. This union method is hence a counter-part of diff and intersect that
* also work on multi-sets.
*
*
* @param that the Every to add.
* @return a new Chain that contains all elements of this Chain followed by all elements of that Every.
*/
final def union[U >: T](that: Every[U]): Chain[U] = new Chain(toList union that.toVector)
/**
* Produces a new Chain that contains all elements of this Chain and also all elements of a given Chain.
*
*
* chainX union chainY is equivalent to chainX ++ chainY.
*
*
*
* Another way to express this is that chainX union chainY computes the order-presevring multi-set union
* of chainX and chainY. This union method is hence a counter-part of diff and intersect that
* also work on multi-sets.
*
*
* @param that the Chain to add.
* @return a new Chain that contains all elements of this Chain followed by all elements of that.
*/
final def union[U >: T](that: Chain[U]): Chain[U] = new Chain(toList union that.toList)
/**
* Produces a new Chain that contains all elements of this Chain and also all elements of a given GenSeq.
*
*
* chainX union ys is equivalent to chainX ++ ys.
*
*
*
* Another way to express this is that chainX union ys computes the order-presevring multi-set union
* of chainX and ys. This union method is hence a counter-part of diff and intersect that
* also work on multi-sets.
*
*
* @param that the GenSeq to add.
* @return a new Chain that contains all elements of this Chain followed by all elements of that GenSeq.
*/
final def union[U >: T](that: GenSeq[U])(implicit cbf: CanBuildFrom[List[T], U, List[U]]): Chain[U] = new Chain(toList.union(that)(cbf))
/**
* Converts this Chain of pairs into two Chains of the first and second half of each pair.
*
* @tparam L the type of the first half of the element pairs
* @tparam R the type of the second half of the element pairs
* @param asPair an implicit conversion that asserts that the element type of this Chain is a pair.
* @return a pair of Chains, containing the first and second half, respectively, of each element pair of this Chain.
*/
final def unzip[L, R](implicit asPair: T => (L, R)): (Chain[L], Chain[R]) = {
val unzipped = toList.unzip
(new Chain(unzipped._1), new Chain(unzipped._2))
}
/**
* Converts this Chain of triples into three Chains of the first, second, and and third element of each triple.
*
* @tparam L the type of the first member of the element triples
* @tparam R the type of the second member of the element triples
* @tparam R the type of the third member of the element triples
* @param asTriple an implicit conversion that asserts that the element type of this Chain is a triple.
* @return a triple of Chains, containing the first, second, and third member, respectively, of each element triple of this Chain.
*/
final def unzip3[L, M, R](implicit asTriple: T => (L, M, R)): (Chain[L], Chain[M], Chain[R]) = {
val unzipped = toList.unzip3
(new Chain(unzipped._1), new Chain(unzipped._2), new Chain(unzipped._3))
}
/**
* A copy of this Chain with one single replaced element.
*
* @param idx the position of the replacement
* @param elem the replacing element
* @throws IndexOutOfBoundsException if the passed index is greater than or equal to the length of this Chain
* @return a copy of this Chain with the element at position idx replaced by elem.
*/
final def updated[U >: T](idx: Int, elem: U): Chain[U] =
try new Chain(toList.updated(idx, elem))
catch { case _: UnsupportedOperationException => throw new IndexOutOfBoundsException(idx.toString) } // This is needed for 2.10 support. Can drop after.
// Because 2.11 throws IndexOutOfBoundsException.
/**
* Returns a Chain formed from this Chain and an iterable collection by combining corresponding
* elements in pairs. If one of the two collections is shorter than the other, placeholder elements will be used to extend the
* shorter collection to the length of the longer.
*
* @tparm O the type of the second half of the returned pairs
* @tparm U the type of the first half of the returned pairs
* @param other the Iterable providing the second half of each result pair
* @param thisElem the element to be used to fill up the result if this Chain is shorter than that Iterable.
* @param thatElem the element to be used to fill up the result if that Iterable is shorter than this Chain.
* @return a new Chain containing pairs consisting of corresponding elements of this Chain and that. The
* length of the returned collection is the maximum of the lengths of this Chain and that. If this Chain
* is shorter than that, thisElem values are used to pad the result. If that is shorter than this
* Chain, thatElem values are used to pad the result.
*/
final def zipAll[O, U >: T](other: collection.Iterable[O], thisElem: U, otherElem: O): Chain[(U, O)] =
new Chain(toList.zipAll(other, thisElem, otherElem))
/**
* Zips this Chain with its indices.
*
* @return A new Chain containing pairs consisting of all elements of this Chain paired with their index. Indices start at 0.
*/
final def zipWithIndex: Chain[(T, Int)] = new Chain(toList.zipWithIndex)
}
/**
* Companion object for class Chain.
*/
object Chain {
/**
* Constructs a new Chain given at least one element.
*
* @tparam T the type of the element contained in the new Chain
* @param firstElement the first element (with index 0) contained in this Chain
* @param otherElements a varargs of zero or more other elements (with index 1, 2, 3, ...) contained in this Chain
*/
def apply[T](firstElement: T, otherElements: T*): Chain[T] = new Chain(firstElement :: otherElements.toList)
/**
* Variable argument extractor for Chains.
*
* @param chain: the Chain containing the elements to extract
* @return an Seq containing this Chains elements, wrapped in a Some
*/
def unapplySeq[T](chain: Chain[T]): Option[Seq[T]] = Some(chain.toList)
/*
// TODO: Figure out how to get case Chain() to not compile
def unapplySeq[T](chain: Chain[T]): Option[(T, Seq[T])] = Some(chain.head, chain.tail)
*/
/**
* Optionally construct a Chain containing the elements, if any, of a given GenSeq.
*
* @param seq the GenSeq with which to construct a Chain
* @return a Chain containing the elements of the given GenSeq, if non-empty, wrapped in
* a Some; else None if the GenSeq is empty
*/
def from[T](seq: GenSeq[T]): Option[Chain[T]] =
seq.headOption match {
case None => None
case Some(first) => Some(new Chain(first :: seq.tail.toList))
}
import scala.language.implicitConversions
/**
* Implicit conversion from Chain to List.
*
*
* One use case for this implicit conversion is to enable GenSeq[Chain]s to be flattened.
* Here's an example:
*
*
*
* scala> Vector(Chain(1, 2, 3), Chain(3, 4), Chain(5, 6, 7, 8)).flatten
* res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3, 3, 4, 5, 6, 7, 8)
*
*
* @param chain the Chain to convert to a List
* @return a List containing the elements, in order, of this Chain
*/
implicit def chainToList[E](chain: Chain[E]): scala.collection.immutable.List[E] = chain.toList
}
/**
* Object that can be used as an endpoint for Chain construction expressions
* that use the cons (::) operator.
*
*
* Here's an example:
*
*
*
* scala> 1 :: 2 :: 3 :: End
* res0: org.scalactic.Chain[Int] = Chain(1, 2, 3)
*
*
*
* Note that unlike Nil, which is an instance of List[Nothing],
* End is not an instance of Chain[Nothing], because there is
* no empty Chain:
*
*
*
* scala> Nil.isInstanceOf[List[_]]
* res0: Boolean = true
*
* scala> End.isInstanceOf[Chain[_]]
* res1: Boolean = false
*
*/
object End {
/**
* A :: operator that serves to start a Chain construction
* expression.
*
*
* The result of calling this method will always be a Chain of length 1.
* Here's an example:
*
*
*
* scala> 1 :: End
* res0: org.scalactic.Chain[Int] = Chain(1)
*
*/
def ::[T](element: T): Chain[T] = Chain(element)
/**
* Returns "End".
*/
override def toString: String = "End"
}