All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cats.data.Chain.scala Maven / Gradle / Ivy

The newest version!
package cats
package data

import Chain._
import cats.kernel.instances.StaticMethods

import scala.annotation.tailrec
import scala.collection.immutable.SortedMap
import scala.collection.immutable.TreeSet
import scala.collection.mutable.ListBuffer

/**
 * Trivial catenable sequence. Supports O(1) append, and (amortized)
 * O(1) `uncons`, such that walking the sequence via N successive `uncons`
 * steps takes O(N).
 */
sealed abstract class Chain[+A] {

  /**
   * Returns the head and tail of this Chain if non empty, none otherwise. Amortized O(1).
   */
  final def uncons: Option[(A, Chain[A])] = {
    var c: Chain[A] = this
    val rights = new collection.mutable.ArrayBuffer[Chain[A]]
    // scalastyle:off null
    var result: Option[(A, Chain[A])] = null
    while (result eq null) {
      c match {
        case Singleton(a) =>
          val next =
            if (rights.isEmpty) nil
            else rights.reduceLeft((x, y) => Append(y, x))
          result = Some(a -> next)
        case Append(l, r) => c = l; rights += r
        case Wrap(seq) =>
          val tail = fromSeq(seq.tail)
          val next =
            if (rights.isEmpty) tail
            else tail ++ rights.reduceLeft((x, y) => Append(y, x))
          result = Some((seq.head, next))
        case Empty =>
          // Empty is only top level, it is never internal to an Append
          result = None
      }
    }
    // scalastyle:on null
    result
  }

  /**
   * Returns the init and last of this Chain if non empty, none otherwise. Amortized O(1).
   */
  final def initLast: Option[(Chain[A], A)] = {
    var c: Chain[A] = this
    val lefts = new collection.mutable.ArrayBuffer[Chain[A]]
    // scalastyle:off null
    var result: Option[(Chain[A], A)] = null
    while (result eq null) {
      c match {
        case Singleton(a) =>
          val pre =
            if (lefts.isEmpty) nil
            else lefts.reduceLeft((x, y) => Append(x, y))
          result = Some(pre -> a)
        case Append(l, r) => c = r; lefts += l
        case Wrap(seq) =>
          val init = fromSeq(seq.init)
          val pre =
            if (lefts.isEmpty) init
            else lefts.reduceLeft((x, y) => Append(x, y)) ++ init
          result = Some((pre, seq.last))
        case Empty =>
          // Empty is only top level, it is never internal to an Append
          result = None
      }
    }
    // scalastyle:on null
    result
  }

  /**
   * Returns the head of this Chain if non empty, none otherwise. Amortized O(1).
   */
  def headOption: Option[A] = uncons.map(_._1)

  /**
   * Returns the last of this Chain if non empty, none otherwise. Amortized O(1).
   */
  final def lastOption: Option[A] = initLast.map(_._2)

  /**
   * Returns true if there are no elements in this collection.
   */
  def isEmpty: Boolean

  /**
   * Returns false if there are no elements in this collection.
   */
  final def nonEmpty: Boolean = !isEmpty

  /**
   * Concatenates this with `c` in O(1) runtime.
   */
  final def concat[A2 >: A](c: Chain[A2]): Chain[A2] =
    Chain.concat(this, c)

  /**
   * Alias for concat
   */
  final def ++[A2 >: A](c: Chain[A2]): Chain[A2] =
    concat(c)

  /**
   * Returns a new Chain consisting of `a` followed by this. O(1) runtime.
   */
  final def prepend[A2 >: A](a: A2): Chain[A2] =
    Chain.concat(one(a), this)

  /**
   * Alias for [[prepend]].
   */
  final def +:[A2 >: A](a: A2): Chain[A2] =
    prepend(a)

  /**
   * Returns a new Chain consisting of this followed by `a`. O(1) runtime.
   */
  final def append[A2 >: A](a: A2): Chain[A2] =
    Chain.concat(this, one(a))

  /**
   * Alias for [[append]].
   */
  final def :+[A2 >: A](a: A2): Chain[A2] =
    append(a)

  /**
   * Applies the supplied function to each element and returns a new Chain.
   */
  final def map[B](f: A => B): Chain[B] = this match {
    case Wrap(seq) => Wrap(seq.map(f))
    case _         => fromSeq(iterator.map(f).toVector)
  }

  /**
   * Applies the supplied function to each element and returns a new Chain from the concatenated results
   */
  final def flatMap[B](f: A => Chain[B]): Chain[B] = {
    var result = empty[B]
    val iter = iterator
    while (iter.hasNext) { result = result ++ f(iter.next) }
    result
  }

  /**
   * Folds over the elements from left to right using the supplied initial value and function.
   */
  final def foldLeft[B](z: B)(f: (B, A) => B): B = {
    var result = z
    val iter = iterator
    while (iter.hasNext) { result = f(result, iter.next) }
    result
  }

  /**
   * Takes longest prefix of elements that satisfy a predicate.
   * @param p The predicate used to test elements.
   * @return the longest prefix of this chain whose elements all satisfy the predicate p.
   */
  final def takeWhile(p: A => Boolean): Chain[A] = {
    var result = Chain.empty[A]
    foreachUntil { a =>
      val pr = p(a)
      if (pr) result = result :+ a
      !pr
    }
    result
  }

  /**
   * Drops longest prefix of elements that satisfy a predicate.
   *
   * @param p The predicate used to test elements.
   * @return the longest suffix of this sequence whose first element does not satisfy the predicate p.
   */
  final def dropWhile(p: A => Boolean): Chain[A] = {
    @tailrec
    def go(rem: Chain[A]): Chain[A] =
      rem.uncons match {
        case Some((a, tail)) =>
          if (p(a)) go(tail)
          else rem

        case None => nil
      }
    go(this)
  }

  /**
   * Folds over the elements from right to left using the supplied initial value and function.
   */
  final def foldRight[B](z: B)(f: (A, B) => B): B = {
    var result = z
    val iter = reverseIterator
    while (iter.hasNext) { result = f(iter.next, result) }
    result
  }

  /**
   * Collect `B` from this for which `f` is defined
   */
  final def collect[B](pf: PartialFunction[A, B]): Chain[B] =
    foldLeft(Chain.nil: Chain[B]) { (acc, a) =>
      // trick from TraversableOnce, used to avoid calling both isDefined and apply (or calling lift)
      val x = pf.applyOrElse(a, sentinel)
      if (x.asInstanceOf[AnyRef] ne sentinel) acc :+ x.asInstanceOf[B]
      else acc
    }

  /**
   * Finds the first element of this `Chain` for which the given partial
   * function is defined, and applies the partial function to it.
   */
  final def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = {
    var result: Option[B] = None
    foreachUntil { a =>
      // trick from TraversableOnce, used to avoid calling both isDefined and apply (or calling lift)
      val x = pf.applyOrElse(a, sentinel)
      if (x.asInstanceOf[AnyRef] ne sentinel) {
        result = Some(x.asInstanceOf[B])
        true
      } else false
    }
    result
  }

  /**
   * Like `collectFirst` from `scala.collection.Traversable` but takes `A => Option[B]`
   * instead of `PartialFunction`s.
   */
  final def collectFirstSome[B](f: A => Option[B]): Option[B] = {
    var result: Option[B] = None
    foreachUntil { a =>
      val x = f(a)
      if (x.isDefined) {
        result = x
        true
      } else false
    }
    result
  }

  /**
   * Remove elements not matching the predicate
   */
  final def filter(f: A => Boolean): Chain[A] =
    collect { case a if f(a) => a }

  /**
   * Remove elements matching the predicate
   */
  final def filterNot(f: A => Boolean): Chain[A] =
    filter(a => !f(a))

  /**
   * Find the first element matching the predicate, if one exists
   */
  final def find(f: A => Boolean): Option[A] = {
    var result: Option[A] = Option.empty[A]
    foreachUntil { a =>
      val b = f(a)
      if (b) result = Option(a)
      b
    }
    result
  }

  /**
   * Check whether at least one element satisfies the predicate
   */
  final def exists(f: A => Boolean): Boolean = {
    var result: Boolean = false
    foreachUntil { a =>
      val b = f(a)
      if (b) result = true
      b
    }
    result
  }

  /**
   * Check whether all elements satisfy the predicate
   */
  final def forall(f: A => Boolean): Boolean = {
    var result: Boolean = true
    foreachUntil { a =>
      val b = f(a)
      if (!b) result = false
      !b
    }
    result
  }

  /**
   * Check whether an element is in this structure
   */
  final def contains[AA >: A](a: AA)(implicit A: Eq[AA]): Boolean =
    exists(A.eqv(a, _))

  /**
   * Zips this `Chain` with another `Chain` and applies a function for each pair of elements.
   */
  final def zipWith[B, C](other: Chain[B])(f: (A, B) => C): Chain[C] =
    if (this.isEmpty || other.isEmpty) Chain.Empty
    else {
      val iterA = iterator
      val iterB = other.iterator

      var result: Chain[C] = Chain.one(f(iterA.next(), iterB.next()))

      while (iterA.hasNext && iterB.hasNext) {
        result = result :+ f(iterA.next(), iterB.next())
      }
      result
    }

  /**
   * Groups elements inside this `Chain` according to the `Order`
   * of the keys produced by the given mapping function.
   */
  final def groupBy[B](f: A => B)(implicit B: Order[B]): SortedMap[B, NonEmptyChain[A]] = {
    implicit val ordering: Ordering[B] = B.toOrdering
    var m = SortedMap.empty[B, NonEmptyChain[A]]
    val iter = iterator

    while (iter.hasNext) {
      val elem = iter.next
      val k = f(elem)

      m.get(k) match {
        case None      => m += ((k, NonEmptyChain.one(elem))); ()
        case Some(cat) => m = m.updated(k, cat :+ elem)
      }
    }
    m
  }

  /**
   * Reverses this `Chain`
   */
  def reverse: Chain[A] =
    fromSeq(reverseIterator.toVector)

  /**
   * Yields to Some(a, Chain[A]) with `a` removed where `f` holds for the first time,
   * otherwise yields None, if `a` was not found
   * Traverses only until `a` is found.
   */
  final def deleteFirst(f: A => Boolean): Option[(A, Chain[A])] = {
    @tailrec
    def go(rem: Chain[A], acc: Chain[A]): Option[(A, Chain[A])] =
      rem.uncons match {
        case Some((a, tail)) =>
          if (!f(a)) go(tail, acc :+ a)
          else Some((a, acc ++ tail))

        case None => None
      }
    go(this, Chain.nil)
  }

  /**
   * Applies the supplied function to each element, left to right.
   */
  final private def foreach(f: A => Unit): Unit = foreachUntil { a =>
    f(a); false
  }

  /**
   * Applies the supplied function to each element, left to right, but stops when true is returned
   */
  // scalastyle:off null return cyclomatic.complexity
  final private def foreachUntil(f: A => Boolean): Unit = {
    var c: Chain[A] = this
    val rights = new collection.mutable.ArrayBuffer[Chain[A]]

    while (c ne null) {
      c match {
        case Singleton(a) =>
          val b = f(a)
          if (b) return ()
          c =
            if (rights.isEmpty) Empty
            else rights.reduceLeft((x, y) => Append(y, x))
          rights.clear()
        case Append(l, r) => c = l; rights += r
        case Wrap(seq) =>
          val iterator = seq.iterator
          while (iterator.hasNext) {
            val b = f(iterator.next)
            if (b) return ()
          }
          c =
            if (rights.isEmpty) Empty
            else rights.reduceLeft((x, y) => Append(y, x))
          rights.clear()
        case Empty =>
          // Empty is only top level, it is never internal to an Append
          c = null
      }
    }
  }
  // scalastyle:on null return cyclomatic.complexity

  final def iterator: Iterator[A] = this match {
    case Wrap(seq) => seq.iterator
    case _         => new ChainIterator[A](this)
  }

  final def reverseIterator: Iterator[A] = this match {
    case Wrap(seq) => seq.reverseIterator
    case _         => new ChainReverseIterator[A](this)
  }

  /**
   * Returns the number of elements in this structure
   */
  final def length: Long = {
    val iter = iterator
    var i: Long = 0
    while (iter.hasNext) { i += 1; iter.next; }
    i
  }

  /**
   * Alias for length
   */
  final def size: Long = length

  /**
   * Converts to a list.
   */
  final def toList: List[A] =
    iterator.toList

  /**
   * Converts to a vector.
   */
  final def toVector: Vector[A] =
    iterator.toVector

  /**
   * Typesafe equality operator.
   *
   * This method is similar to == except that it only allows two
   * Chain[A] values to be compared to each other, and uses
   * equality provided by Eq[_] instances, rather than using the
   * universal equality provided by .equals.
   */
  def ===[AA >: A](that: Chain[AA])(implicit A: Eq[AA]): Boolean =
    (this eq that) || {
      val iterX = iterator
      val iterY = that.iterator
      while (iterX.hasNext && iterY.hasNext) {
        // scalastyle:off return
        if (!A.eqv(iterX.next, iterY.next)) return false
        // scalastyle:on return
      }

      iterX.hasNext == iterY.hasNext
    }

  /**
   * Remove duplicates. Duplicates are checked using `Order[_]` instance.
   */
  def distinct[AA >: A](implicit O: Order[AA]): Chain[AA] = {
    implicit val ord: Ordering[AA] = O.toOrdering

    var alreadyIn = TreeSet.empty[AA]

    foldLeft(Chain.empty[AA]) { (elementsSoFar, b) =>
      if (alreadyIn.contains(b)) {
        elementsSoFar
      } else {
        alreadyIn += b
        elementsSoFar :+ b
      }
    }
  }

  def show[AA >: A](implicit AA: Show[AA]): String = {
    val builder = new StringBuilder("Chain(")
    var first = true

    foreach { a =>
      if (first) {
        builder ++= AA.show(a); first = false
      } else builder ++= ", " + AA.show(a)
      ()
    }
    builder += ')'
    builder.result
  }

  def hash[AA >: A](implicit hashA: Hash[AA]): Int = StaticMethods.orderedHash((this: Chain[AA]).iterator)

  override def toString: String = show(Show.show[A](_.toString))

  override def equals(o: Any): Boolean =
    if (o.isInstanceOf[Chain[_]])
      (this: Chain[Any]).===(o.asInstanceOf[Chain[Any]])(Eq.fromUniversalEquals[Any])
    else false

  override def hashCode: Int = hash(Hash.fromUniversalHashCode[A])

  final def get(idx: Long): Option[A] =
    if (idx < 0) None
    else {
      var result: Option[A] = None
      var i = 0L
      foreachUntil { a =>
        if (idx == i) {
          result = Some(a)
          true
        } else {
          i += 1
          false
        }
      }
      result
    }
}

object Chain extends ChainInstances {

  private val sentinel: Function1[Any, Any] = new scala.runtime.AbstractFunction1[Any, Any] { def apply(a: Any) = this }

  private[data] case object Empty extends Chain[Nothing] {
    def isEmpty: Boolean = true
  }
  final private[data] case class Singleton[A](a: A) extends Chain[A] {
    def isEmpty: Boolean = false
  }
  final private[data] case class Append[A](left: Chain[A], right: Chain[A]) extends Chain[A] {
    def isEmpty: Boolean =
      false // b/c `concat` constructor doesn't allow either branch to be empty
  }
  final private[data] case class Wrap[A](seq: Seq[A]) extends Chain[A] {
    override def isEmpty: Boolean =
      false // b/c `fromSeq` constructor doesn't allow either branch to be empty
  }

  def unapplySeq[A](chain: Chain[A]): Option[Seq[A]] =
    Some(chain.toList)

  object ==: {
    def unapply[T](c: Chain[T]): Option[(T, Chain[T])] =
      c.uncons
  }

  object :== {
    def unapply[T](c: Chain[T]): Option[(Chain[T], T)] =
      c.initLast
  }

  /** Empty Chain. */
  val nil: Chain[Nothing] = Empty

  def empty[A]: Chain[A] = nil

  /** Creates a Chain of 1 element. */
  def one[A](a: A): Chain[A] = Singleton(a)

  /** Concatenates two Chains. */
  def concat[A](c: Chain[A], c2: Chain[A]): Chain[A] =
    if (c.isEmpty) c2
    else if (c2.isEmpty) c
    else Append(c, c2)

  /** Creates a Chain from the specified sequence. */
  def fromSeq[A](s: Seq[A]): Chain[A] =
    if (s.isEmpty) nil
    else if (s.lengthCompare(1) == 0) one(s.head)
    else Wrap(s)

  /** Creates a Chain from the specified elements. */
  def apply[A](as: A*): Chain[A] =
    fromSeq(as)

  // scalastyle:off null
  private class ChainIterator[A](self: Chain[A]) extends Iterator[A] {
    private[this] var c: Chain[A] = if (self.isEmpty) null else self
    private[this] val rights = new collection.mutable.ArrayBuffer[Chain[A]]
    private[this] var currentIterator: Iterator[A] = null

    override def hasNext: Boolean = (c ne null) || ((currentIterator ne null) && currentIterator.hasNext)

    override def next(): A = {
      @tailrec def go: A =
        if ((currentIterator ne null) && currentIterator.hasNext)
          currentIterator.next()
        else {
          currentIterator = null

          c match {
            case Singleton(a) =>
              c =
                if (rights.isEmpty) null
                else rights.reduceLeft((x, y) => Append(y, x))
              rights.clear()
              a
            case Append(l, r) =>
              c = l
              rights += r
              go
            case Wrap(seq) =>
              c =
                if (rights.isEmpty) null
                else rights.reduceLeft((x, y) => Append(y, x))
              rights.clear()
              currentIterator = seq.iterator
              currentIterator.next
            case null | Empty =>
              throw new java.util.NoSuchElementException("next called on empty iterator")
          }
        }

      go
    }
  }
  // scalastyle:on null

  // scalastyle:off null
  private class ChainReverseIterator[A](self: Chain[A]) extends Iterator[A] {
    private[this] var c: Chain[A] = if (self.isEmpty) null else self
    private[this] val lefts = new collection.mutable.ArrayBuffer[Chain[A]]
    private[this] var currentIterator: Iterator[A] = null

    override def hasNext: Boolean = (c ne null) || ((currentIterator ne null) && currentIterator.hasNext)

    override def next(): A = {
      @tailrec def go: A =
        if ((currentIterator ne null) && currentIterator.hasNext)
          currentIterator.next()
        else {
          currentIterator = null

          c match {
            case Singleton(a) =>
              c =
                if (lefts.isEmpty) null
                else lefts.reduceLeft((x, y) => Append(x, y))
              lefts.clear()
              a
            case Append(l, r) =>
              c = r
              lefts += l
              go
            case Wrap(seq) =>
              c =
                if (lefts.isEmpty) null
                else lefts.reduceLeft((x, y) => Append(x, y))
              lefts.clear()
              currentIterator = seq.reverseIterator
              currentIterator.next
            case null | Empty =>
              throw new java.util.NoSuchElementException("next called on empty iterator")
          }
        }

      go
    }
  }
  // scalastyle:on null
}

sealed abstract private[data] class ChainInstances extends ChainInstances1 {
  implicit def catsDataMonoidForChain[A]: Monoid[Chain[A]] = new Monoid[Chain[A]] {
    def empty: Chain[A] = Chain.nil
    def combine(c: Chain[A], c2: Chain[A]): Chain[A] = Chain.concat(c, c2)
  }

  implicit val catsDataInstancesForChain
    : Traverse[Chain] with Alternative[Chain] with Monad[Chain] with CoflatMap[Chain] with Align[Chain] =
    new Traverse[Chain] with Alternative[Chain] with Monad[Chain] with CoflatMap[Chain] with Align[Chain] {
      def foldLeft[A, B](fa: Chain[A], b: B)(f: (B, A) => B): B =
        fa.foldLeft(b)(f)
      def foldRight[A, B](fa: Chain[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] = {
        def loop(as: Chain[A]): Eval[B] =
          // In Scala 2 the compiler silently ignores the fact that it can't
          // prove that this match is exhaustive, but Dotty warns, so we
          // explicitly mark it as unchecked.
          (as: @unchecked) match {
            case Chain.nil => lb
            case h ==: t   => f(h, Eval.defer(loop(t)))
          }
        Eval.defer(loop(fa))
      }

      override def map[A, B](fa: Chain[A])(f: A => B): Chain[B] = fa.map(f)
      override def toList[A](fa: Chain[A]): List[A] = fa.toList
      override def isEmpty[A](fa: Chain[A]): Boolean = fa.isEmpty
      override def exists[A](fa: Chain[A])(p: A => Boolean): Boolean = fa.exists(p)
      override def forall[A](fa: Chain[A])(p: A => Boolean): Boolean = fa.forall(p)
      override def find[A](fa: Chain[A])(f: A => Boolean): Option[A] = fa.find(f)
      override def size[A](fa: Chain[A]): Long = fa.length
      override def collectFirst[A, B](fa: Chain[A])(pf: PartialFunction[A, B]): Option[B] = fa.collectFirst(pf)
      override def collectFirstSome[A, B](fa: Chain[A])(f: A => Option[B]): Option[B] = fa.collectFirstSome(f)

      def coflatMap[A, B](fa: Chain[A])(f: Chain[A] => B): Chain[B] = {
        @tailrec def go(as: Chain[A], res: ListBuffer[B]): Chain[B] =
          as.uncons match {
            case Some((_, t)) => go(t, res += f(as))
            case None         => Chain.fromSeq(res.result())
          }

        go(fa, ListBuffer.empty)
      }

      def traverse[G[_], A, B](fa: Chain[A])(f: A => G[B])(implicit G: Applicative[G]): G[Chain[B]] =
        foldRight[A, G[Chain[B]]](fa, Always(G.pure(nil))) { (a, lglb) =>
          G.map2Eval(f(a), lglb)(_ +: _)
        }.value
      def empty[A]: Chain[A] = Chain.nil
      def combineK[A](c: Chain[A], c2: Chain[A]): Chain[A] = Chain.concat(c, c2)
      def pure[A](a: A): Chain[A] = Chain.one(a)
      def flatMap[A, B](fa: Chain[A])(f: A => Chain[B]): Chain[B] =
        fa.flatMap(f)
      def tailRecM[A, B](a: A)(f: A => Chain[Either[A, B]]): Chain[B] = {
        var acc: Chain[B] = Chain.nil
        @tailrec def go(rest: List[Chain[Either[A, B]]]): Unit =
          rest match {
            case hd :: tl =>
              hd.uncons match {
                case Some((hdh, hdt)) =>
                  hdh match {
                    case Right(b) =>
                      acc = acc :+ b
                      go(hdt :: tl)
                    case Left(a) =>
                      go(f(a) :: hdt :: tl)
                  }
                case None =>
                  go(tl)
              }
            case _ => ()
          }
        go(f(a) :: Nil)
        acc
      }

      override def get[A](fa: Chain[A])(idx: Long): Option[A] = fa.get(idx)

      def functor: Functor[Chain] = this

      def align[A, B](fa: Chain[A], fb: Chain[B]): Chain[Ior[A, B]] =
        alignWith(fa, fb)(identity)

      override def alignWith[A, B, C](fa: Chain[A], fb: Chain[B])(f: Ior[A, B] => C): Chain[C] = {
        val iterA = fa.iterator
        val iterB = fb.iterator

        var result: Chain[C] = Chain.empty

        while (iterA.hasNext || iterB.hasNext) {
          val ior =
            if (iterA.hasNext && iterB.hasNext) Ior.both(iterA.next(), iterB.next())
            else if (iterA.hasNext) Ior.left(iterA.next())
            else Ior.right(iterB.next())
          result = result :+ f(ior)
        }
        result
      }
    }

  implicit def catsDataShowForChain[A](implicit A: Show[A]): Show[Chain[A]] =
    Show.show[Chain[A]](_.show)

  implicit def catsDataOrderForChain[A](implicit A0: Order[A]): Order[Chain[A]] =
    new Order[Chain[A]] with ChainPartialOrder[A] {
      implicit def A: PartialOrder[A] = A0
      def compare(x: Chain[A], y: Chain[A]): Int =
        if (x eq y) 0
        else {
          val iterX = x.iterator
          val iterY = y.iterator
          while (iterX.hasNext && iterY.hasNext) {
            val n = A0.compare(iterX.next, iterY.next)
            // scalastyle:off return
            if (n != 0) return n
            // scalastyle:on return
          }

          if (iterX.hasNext) 1
          else if (iterY.hasNext) -1
          else 0
        }
    }

  implicit val catsDataTraverseFilterForChain: TraverseFilter[Chain] = new TraverseFilter[Chain] {
    def traverse: Traverse[Chain] = Chain.catsDataInstancesForChain

    override def filter[A](fa: Chain[A])(f: A => Boolean): Chain[A] = fa.filter(f)

    override def filterNot[A](fa: Chain[A])(f: A => Boolean): Chain[A] = fa.filterNot(f)

    override def collect[A, B](fa: Chain[A])(f: PartialFunction[A, B]): Chain[B] = fa.collect(f)

    override def mapFilter[A, B](fa: Chain[A])(f: A => Option[B]): Chain[B] = fa.collect(Function.unlift(f))

    override def flattenOption[A](fa: Chain[Option[A]]): Chain[A] = fa.collect { case Some(a) => a }

    def traverseFilter[G[_], A, B](fa: Chain[A])(f: A => G[Option[B]])(implicit G: Applicative[G]): G[Chain[B]] =
      traverse
        .foldRight(fa, Eval.now(G.pure(Chain.empty[B])))(
          (x, xse) => G.map2Eval(f(x), xse)((i, o) => i.fold(o)(_ +: o))
        )
        .value

    override def filterA[G[_], A](fa: Chain[A])(f: A => G[Boolean])(implicit G: Applicative[G]): G[Chain[A]] =
      traverse
        .foldRight(fa, Eval.now(G.pure(Chain.empty[A])))(
          (x, xse) => G.map2Eval(f(x), xse)((b, chain) => if (b) x +: chain else chain)
        )
        .value

  }

}

sealed abstract private[data] class ChainInstances1 extends ChainInstances2 {
  implicit def catsDataPartialOrderForChain[A](implicit A0: PartialOrder[A]): PartialOrder[Chain[A]] =
    new ChainPartialOrder[A] { implicit def A: PartialOrder[A] = A0 }
}

sealed abstract private[data] class ChainInstances2 extends ChainInstances3 {
  implicit def catsDataHashForChain[A](implicit A: Hash[A]): Hash[Chain[A]] = new Hash[Chain[A]] {
    def eqv(x: Chain[A], y: Chain[A]): Boolean = x === y

    def hash(fa: Chain[A]): Int = fa.hash
  }
}

sealed abstract private[data] class ChainInstances3 {
  implicit def catsDataEqForChain[A](implicit A: Eq[A]): Eq[Chain[A]] = new Eq[Chain[A]] {
    def eqv(x: Chain[A], y: Chain[A]): Boolean = x === y
  }
}

private[data] trait ChainPartialOrder[A] extends PartialOrder[Chain[A]] {
  implicit def A: PartialOrder[A]

  override def partialCompare(x: Chain[A], y: Chain[A]): Double =
    if (x eq y) 0.0
    else {
      val iterX = x.iterator
      val iterY = y.iterator
      while (iterX.hasNext && iterY.hasNext) {
        val n = A.partialCompare(iterX.next, iterY.next)
        // scalastyle:off return
        if (n != 0.0) return n
        // scalastyle:on return
      }

      if (iterX.hasNext) 1.0
      else if (iterY.hasNext) -1.0
      else 0.0
    }

  override def eqv(x: Chain[A], y: Chain[A]): Boolean = x === y
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy