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

nyaya.test.Domain.scala Maven / Gradle / Ivy

package nyaya.test

import cats.Functor
import scala.collection.Factory
import scala.collection.immutable.NumericRange
import scala.reflect.ClassTag

trait Domain[A] {
  val size: Int
  def apply(i: Int): A

  def subst[B >: A]: Domain[B] =
    map(a => a)

  def map[B](f: A => B): Domain[B] =
    new Domain.Mapped(this, f)

  def option: Domain[Option[A]] =
    new Domain.OptionT(this)

  def either[B](b: Domain[B]): Domain[Either[A, B]] =
    this +++ b

  def +++[B](b: Domain[B]): Domain[Either[A, B]] =
    new Domain.Disjunction(this, b)

  def ***[B](b: Domain[B]): Domain[(A, B)] =
    new Domain.Pair(this, b)

  def pair: Domain[(A, A)] =
    this *** this

  def triple: Domain[(A, A, A)] =
    this *** pair map (t => (t._1, t._2._1, t._2._2))

  def seq[S[_]](r: Range)(implicit c: Factory[A, S[A]]): Domain[S[A]] =
    new Domain.IntoSeq(this, r)(c)

  def array(s: Int)  (implicit t: ClassTag[A]): Domain[Array[A]] = seq[Array](s to s)
  def array(r: Range)(implicit t: ClassTag[A]): Domain[Array[A]] = seq[Array](r)

  def list(s: Int)  : Domain[List[A]] = seq[List](s to s)
  def list(r: Range): Domain[List[A]] = seq[List](r)

  def vector(s: Int)  : Domain[Vector[A]] = seq[Vector](s to s)
  def vector(r: Range): Domain[Vector[A]] = seq[Vector](r)

  def iterator: Iterator[A] =
    (0 until size).iterator.map(apply)
}

object Domain {

  implicit val domainInstance: Functor[Domain] = new Functor[Domain] {
    override def map[A, B](fa: Domain[A])(f: A => B): Domain[B] = fa map f
  }

  final class Mapped[A, B](u: Domain[A], f: A => B) extends Domain[B] {
    override val size = u.size
    override def apply(i: Int) = f(u(i))
    override def map[C](g: B => C): Domain[C] =
      new Domain.Mapped(u, g compose f)
  }

  final class OptionT[A](u: Domain[A]) extends Domain[Option[A]] {
    override val size = u.size + 1
    override def apply(i: Int) = if (i == 0) None else Some(u(i - 1))
  }

  final class Disjunction[A, B](a: Domain[A], b: Domain[B]) extends Domain[Either[A, B]] {
    private[this] val as = a.size
    override val size = as + b.size
    override def apply(i: Int) = if (i < as) Left(a(i)) else Right(b(i - as))
  }

  final class Pair[A, B](a: Domain[A], b: Domain[B]) extends Domain[(A, B)] {
    private[this] val as = a.size
    override val size = as * b.size
    override def apply(i: Int) = (a(i % as), b(i / as))
  }

  final class OverSeq[A](as: IndexedSeq[A]) extends Domain[A] {
    override val size = as.length
    override def apply(i: Int) = as(i)
  }

  final class IntoSeq[S[_], A](a: Domain[A], r: Range)(implicit c: Factory[A, S[A]]) extends Domain[S[A]] {
    private[this] val as = a.size
    val (size, starts) = r.foldLeft((0, Vector.empty[Int])) {
      case ((sum, q), i) => (sum + (if (i == 0) 1 else math.pow(as, i).toInt), q :+ sum)
    }
    override def apply(i0: Int): S[A] = {
      var i = i0
      var s = starts.length - 1
      while (s > 0 && i < starts(s)) s -= 1
      var seqSize = r(s)
      i -= starts(s)
      val builder = c.newBuilder
      while (seqSize > 0) {
        builder += a(i % as)
        i /= as
        seqSize -= 1
      }
      builder.result()
    }
  }

  def ofValues[A](as: A*): Domain[A] =
    new OverSeq[A](as.toIndexedSeq)

  def ofRange(r: Range): Domain[Int] =
    new OverSeq[Int](r)

  def ofRangeN[A](r: NumericRange[A]): Domain[A] =
    new OverSeq[A](r)

  val boolean: Domain[Boolean] =
    ofValues(true, false)

  lazy val byte: Domain[Byte] =
    ofRange(Byte.MinValue to Byte.MaxValue).map(_.toByte)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy