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

cats.derived.iterable.scala Maven / Gradle / Ivy

/*
 * Copyright (c) 2015 Miles Sabin
 *
 * 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 cats.derived

import scala.annotation.tailrec

import shapeless._

object iterable {
  object legacy {
    implicit def mkIterableLegacy[F[_], A](fa: F[A])(implicit mif: MkIterable[F]): Iterable[A] =
      mif.iterable(fa)
  }
}

trait MkIterable[F[_]] {
  import IterState._

  def initialState[A](fa: F[A]): IterState[A]

  def iterable[A](fa: F[A]): Iterable[A] =
    new Iterable[A] {
      lazy val initial: IterState[A] = initialState(fa)
      def iterator: Iterator[A] =
        new Iterator[A] {
          var first = initial
          var rest: List[() => IterState[A]] = Nil

          @tailrec
          def hasNext: Boolean =
            first match {
              case Return(_) => true
              case ReturnI(ia) =>
                if(ia.hasNext) true
                else if(rest.isEmpty) false
                else {
                  first = rest.head()
                  rest = rest.tail
                  hasNext
                }
              case Cont(hd, tl) =>
                first = hd
                rest = tl :: rest
                hasNext
              case Done =>
                if(rest.isEmpty) false
                else {
                  first = rest.head()
                  rest = rest.tail
                  hasNext
                }
            }

          def next: A = {
            if(!hasNext)
              throw new NoSuchElementException("next on empty iterator")
            (first: @unchecked) match {
              case Return(a) =>
                first = Done
                a
              case ReturnI(ia) =>
                ia.next
            }
          }
        }
    }
}

sealed trait IterState[+A]
object IterState {
  case class Return[A](a: A) extends IterState[A]
  case class ReturnI[A](ia: Iterator[A]) extends IterState[A]
  case class Cont[A](hd: IterState[A], tl: () => IterState[A]) extends IterState[A]
  case object Done extends IterState[Nothing]
}

object MkIterable extends MkIterable0 {
  import IterState._

  def apply[F[_]](implicit mif: MkIterable[F]): MkIterable[F] = mif

  implicit val id: MkIterable[Id] =
    new MkIterable[Id] {
      def initialState[A](fa: A): IterState[A] = Return(fa)
    }

  implicit val option: MkIterable[Option] =
    new MkIterable[Option] {
      def initialState[A](fa: Option[A]): IterState[A] = ReturnI(fa.iterator)
    }

  implicit def iterable[F[t] <: Iterable[t]]: MkIterable[F] =
    new MkIterable[F] {
      def initialState[A](fa: F[A]): IterState[A] =
        ReturnI(fa.iterator)
    }
}

trait MkIterable0 extends MkIterable1 {
  import IterState._

  implicit def hcons[F[_]](implicit F: IsHCons1[F, MkIterable, MkIterable]): MkIterable[F] =
    new MkIterable[F] {
      def initialState[A](fa: F[A]): IterState[A] = {
        val (hd, tl) = F.unpack(fa)
        if(tl == HNil) F.fh.initialState(hd)
        else Cont(F.fh.initialState(hd), () => F.ft.initialState(tl))
      }
    }

  implicit def ccons[F[_]](implicit F: IsCCons1[F, MkIterable, MkIterable]): MkIterable[F] =
    new MkIterable[F] {
      def initialState[A](fa: F[A]): IterState[A] = {
        F.unpack(fa) match {
          case Left(hd) => F.fh.initialState(hd)
          case Right(tl) => F.ft.initialState(tl)
        }
      }
    }
}

trait MkIterable1 extends MkIterable2 {
  import IterState._

  implicit def split[F[_]](implicit split: Split1[F, MkIterable, MkIterable]): MkIterable[F] =
    new MkIterable[F] {
      def initialState[A](fa: F[A]): IterState[A] = {
        import split._
        ReturnI(fo.iterable(unpack(fa)).iterator.flatMap { ia => fi.iterable(ia).iterator })
      }
    }
}

trait MkIterable2 extends MkIterable3 {
  implicit def generic[F[_]](implicit F: Generic1[F, MkIterable]): MkIterable[F] =
    new MkIterable[F] {
      def initialState[A](fa: F[A]): IterState[A] = F.fr.initialState(F.to(fa))
    }
}

trait MkIterable3 {
  import IterState._

  implicit def const[T]: MkIterable[Const[T]#λ] =
    new MkIterable[Const[T]#λ] {
      def initialState[A](fa: T): IterState[A] = Done
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy