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

scalaz.ImmutableArray.scala Maven / Gradle / Ivy

The newest version!
package scalaz

import reflect.ClassTag
import scala.collection.immutable.IndexedSeq
import scala.collection.mutable.{ArrayBuilder, Builder}
import syntax.Ops

/**
 * An immutable wrapper for arrays
 *
 * @tparam A type of the elements of the array
 */
sealed abstract class ImmutableArray[+A] {

  // these methods are not total
  private[scalaz] def apply(index: Int): A
  private[scalaz] def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit

  def length: Int

  def isEmpty: Boolean = length == 0

  def toArray[B >: A : ClassTag]: Array[B]
  def slice(from: Int, until: Int): ImmutableArray[A]

  def ++[B >: A: ClassTag](other: ImmutableArray[B]): ImmutableArray[B]
}

sealed abstract class ImmutableArrayInstances {

  implicit def immutableArrayEqual[A](implicit A: Equal[A]): Equal[ImmutableArray[A]] =
    Equal.equal{ (a, b) =>
      (a.length == b.length) && (0 until a.length).forall(i => A.equal(a(i), b(i)))
    }

  implicit val immutableArrayInstance: Foldable[ImmutableArray] & Zip[ImmutableArray] =
    new Foldable[ImmutableArray] with Zip[ImmutableArray] {
      override def foldLeft[A, B](fa: ImmutableArray[A], z: B)(f: (B, A) => B) =
        fa.foldLeft(z)(f)
      def foldMap[A, B](fa: ImmutableArray[A])(f: A => B)(implicit F: Monoid[B]): B = {
        @annotation.tailrec
        def loop(i: Int, b: B): B = {
          if (i < fa.length) {
            loop(i + 1, F.append(b, f(fa(i))))
          } else {
            b
          }
        }
        loop(0, F.zero)
      }
      def foldRight[A, B](fa: ImmutableArray[A], z: => B)(f: (A, => B) => B) =
        fa.foldRight(z)((a, b) => f(a, b))
      def zip[A, B](a: => ImmutableArray[A], b: => ImmutableArray[B]) = {
        val _a = a
        if(_a.isEmpty) new ImmutableArray.ofRef(Array[(A, B)]())
        else new ImmutableArray.ofRef((_a.iterator zip b.iterator).toArray)
      }
      override def index[A](fa: ImmutableArray[A], i: Int) =
        if(0 <= i && i < fa.length) Some(fa(i)) else None
      override def length[A](fa: ImmutableArray[A]) =
        fa.length
      override def empty[A](fa: ImmutableArray[A]) =
        fa.isEmpty
      override def all[A](fa: ImmutableArray[A])(f: A => Boolean) = {
        val len = fa.length
        @annotation.tailrec
        def loop(i: Int): Boolean = {
          if(i < len) f(fa(i)) && loop(i + 1)
          else true
        }
        loop(0)
      }
      override def any[A](fa: ImmutableArray[A])(f: A => Boolean) = {
        val len = fa.length
        @annotation.tailrec
        def loop(i: Int): Boolean = {
          if(i < len) f(fa(i)) || loop(i + 1)
          else false
        }
        loop(0)
      }

    }
}

object ImmutableArray extends ImmutableArrayInstances {

  def make[A](x: AnyRef): ImmutableArray[A] = {
    val y: ImmutableArray[?] = x match {
      case null              => null
      case x: Array[Byte]    => new ofByte(x)
      case x: Array[Short]   => new ofShort(x)
      case x: Array[Char]    => new ofChar(x)
      case x: Array[Int]     => new ofInt(x)
      case x: Array[Long]    => new ofLong(x)
      case x: Array[Float]   => new ofFloat(x)
      case x: Array[Double]  => new ofDouble(x)
      case x: Array[Boolean] => new ofBoolean(x)
      case x: Array[Unit]    => new ofUnit(x)
      case x: Array[AnyRef]  => new ofRef(x)
      case x: String         => new StringArray(x)
    }
    y.asInstanceOf[ImmutableArray[A]]
  }

  /**
   * Wrap `x` in an `ImmutableArray`.
   *
   * Provides better type inference than `make[A]`
   */
  def fromArray[A](x: Array[A]): ImmutableArray[A] = {
    val y: ImmutableArray[?] = x match {
      case null              => null
      case x: Array[Byte]    => new ofByte(x)
      case x: Array[Short]   => new ofShort(x)
      case x: Array[Char]    => new ofChar(x)
      case x: Array[Int]     => new ofInt(x)
      case x: Array[Long]    => new ofLong(x)
      case x: Array[Float]   => new ofFloat(x)
      case x: Array[Double]  => new ofDouble(x)
      case x: Array[Boolean] => new ofBoolean(x)
      case x: Array[Unit]    => new ofUnit(x)
      case x: Array[AnyRef]  => new ofRef(x)
    }
    y.asInstanceOf[ImmutableArray[A]]
  }

  /** Wrap the characters in `str` in an `ImmutableArray` */
  def fromString(str: String): ImmutableArray[Char] = new StringArray(str)

  def newBuilder[A](implicit elemTag: ClassTag[A]): Builder[A, ImmutableArray[A]] =
    ArrayBuilder.make[A].mapResult(make(_))

  def newStringArrayBuilder: Builder[Char, ImmutableArray[Char]] =
    (new StringBuilder).mapResult(fromString(_))

  sealed abstract class ImmutableArray1[+A](array: Array[A]) extends ImmutableArray[A] {
    private[this] val arr = array.clone

    def componentType: Class[_] = arr.getClass().getComponentType

    def apply(idx: Int) = arr(idx)

    def length = arr.length
    def toArray[B >: A : ClassTag] = arr.clone.asInstanceOf[Array[B]]
    def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = { arr.copyToArray(xs, start, len) }

    def slice(from: Int, until: Int) = fromArray(arr.slice(from, until))

    // TODO can do O(1) for primitives
    override def ++[B >: A: ClassTag](other: ImmutableArray[B]): ImmutableArray[B] = {
      val newArr = new Array[B](length + other.length)
      this.copyToArray(newArr, 0, length)
      other.copyToArray(newArr, length, other.length)
      fromArray(newArr)
    }
  }
  final class ofRef[A <: AnyRef](array: Array[A]) extends ImmutableArray1[A](array) {
  }

  final class ofByte(array: Array[Byte]) extends ImmutableArray1[Byte](array) {
  }

  final class ofShort(array: Array[Short]) extends ImmutableArray1[Short](array) {
  }

  final class ofChar(array: Array[Char]) extends ImmutableArray1[Char](array) {
  }

  final class ofInt(array: Array[Int]) extends ImmutableArray1[Int](array) {
  }

  final class ofLong(array: Array[Long]) extends ImmutableArray1[Long](array) {
  }

  final class ofFloat(array: Array[Float]) extends ImmutableArray1[Float](array) {
  }

  final class ofDouble(array: Array[Double]) extends ImmutableArray1[Double](array) {
  }

  final class ofBoolean(array: Array[Boolean]) extends ImmutableArray1[Boolean](array) {
  }

  final class ofUnit(array: Array[Unit]) extends ImmutableArray1[Unit](array) {
  }

  final class StringArray(val str: String) extends ImmutableArray[Char] {
    def apply(idx: Int) = str(idx)

    def length = str.length
    def toArray[B >: Char : ClassTag] = str.toArray
    def copyToArray[B >: Char](xs: Array[B], start: Int, len: Int): Unit = {
      xs match {
        case xs0: Array[Char] =>
          str.copyToArray(xs0, start, len)
        case _ =>
          str.toCharArray.copyToArray(xs, start, len)
      }
    }

    def slice(from: Int, until: Int): ImmutableArray[Char] = new StringArray(str.slice(from, until))

    def ++[B >: Char: ClassTag](other: ImmutableArray[B]) =
      other match {
        case other: StringArray => new StringArray(str + other.str)
        case _ => {
          val newArr = new Array[B](length + other.length)
          this.copyToArray(newArr, 0, length)
          other.copyToArray(newArr, length, other.length)
          fromArray(newArr)
        }
      }
  }

  implicit def wrapArray[A](immArray: ImmutableArray[A]): WrappedImmutableArray[A] = {
    import ImmutableArray.{WrappedImmutableArray => IAO}
    immArray match {
      case a: StringArray => new IAO.ofStringArray(a)
      case a: ofRef[_] => new IAO.ofRef(a)
      case a: ofByte => new IAO.ofByte(a)
      case a: ofShort => new IAO.ofShort(a)
      case a: ofChar => new IAO.ofChar(a)
      case a: ofInt => new IAO.ofInt(a)
      case a: ofLong => new IAO.ofLong(a)
      case a: ofFloat => new IAO.ofFloat(a)
      case a: ofDouble => new IAO.ofDouble(a)
      case a: ofBoolean => new IAO.ofBoolean(a)
      case a: ofUnit => new IAO.ofUnit(a)
    }
  }

  implicit def unwrapArray[A](immArrayOps: WrappedImmutableArray[A]): ImmutableArray[A] = immArrayOps.value

  abstract class WrappedImmutableArray[+A](val value: ImmutableArray[A]) extends
          IndexedSeq[A] {
    def apply(index: Int) = value(index)
    def length = value.length
  }

  object WrappedImmutableArray {
    import scalaz.{ImmutableArray => IA}
    class ofStringArray(val strArray: StringArray) extends WrappedImmutableArray[Char](strArray) {
    }

    abstract class ofImmutableArray1[+A](val immArray: ImmutableArray1[A]) extends WrappedImmutableArray[A](immArray) {
    }

    final class ofRef[+A <: AnyRef](array: IA.ofRef[A]) extends ofImmutableArray1[A](array) {
    }

    final class ofByte(array: IA.ofByte) extends ofImmutableArray1[Byte](array) {
    }

    final class ofShort(array: IA.ofShort) extends ofImmutableArray1[Short](array) {
    }

    final class ofChar(array: IA.ofChar) extends ofImmutableArray1[Char](array) {
    }

    final class ofInt(array: IA.ofInt) extends ofImmutableArray1[Int](array) {
    }

    final class ofLong(array: IA.ofLong) extends ofImmutableArray1[Long](array) {
    }

    final class ofFloat(array: IA.ofFloat) extends ofImmutableArray1[Float](array) {
    }

    final class ofDouble(array: IA.ofDouble) extends ofImmutableArray1[Double](array) {
    }

    final class ofBoolean(array: IA.ofBoolean) extends ofImmutableArray1[Boolean](array) {
    }

    final class ofUnit(array: IA.ofUnit) extends ofImmutableArray1[Unit](array) {
    }
  }

  sealed class ImmutableArrayCharW(val self: ImmutableArray[Char]) extends Ops[ImmutableArray[Char]] {
    def asString: String = self match {
      case a: StringArray => a.str
      case a: ofChar => wrapArray(a).mkString
      case _ => sys.error("Unknown subtype of ImmutableArray[Char]")
    }
  }

  implicit def wrapRopeChar(array: ImmutableArray[Char]): ImmutableArrayCharW = new ImmutableArrayCharW(array)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy