PageRenderTime 60ms CodeModel.GetById 33ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/core/src/main/scala/scalaz/ImmutableArray.scala

http://github.com/scalaz/scalaz
Scala | 323 lines | 247 code | 58 blank | 18 comment | 14 complexity | c8dd6f6fa28bac4ada2cc652f275513e MD5 | raw file
  1package scalaz
  2
  3import reflect.ClassTag
  4import scala.collection.immutable.IndexedSeq
  5import scala.collection.mutable.{ArrayBuilder, Builder}
  6import syntax.Ops
  7
  8/**
  9 * An immutable wrapper for arrays
 10 *
 11 * @tparam A type of the elements of the array
 12 */
 13sealed abstract class ImmutableArray[+A] {
 14  protected[this] def elemTag: ClassTag[A]
 15
 16  // these methods are not total
 17  private[scalaz] def apply(index: Int): A
 18  private[scalaz] def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit
 19
 20  def length: Int
 21
 22  def isEmpty: Boolean = length == 0
 23
 24  def toArray[B >: A : ClassTag]: Array[B]
 25  def slice(from: Int, until: Int): ImmutableArray[A]
 26
 27  def ++[B >: A: ClassTag](other: ImmutableArray[B]): ImmutableArray[B]
 28}
 29
 30sealed abstract class ImmutableArrayInstances {
 31
 32  implicit def immutableArrayEqual[A](implicit A: Equal[A]): Equal[ImmutableArray[A]] =
 33    Equal.equal{ (a, b) =>
 34      (a.length == b.length) && (0 until a.length).forall(i => A.equal(a(i), b(i)))
 35    }
 36
 37  implicit val immutableArrayInstance: Foldable[ImmutableArray] with Zip[ImmutableArray] =
 38    new Foldable[ImmutableArray] with Zip[ImmutableArray] {
 39      override def foldLeft[A, B](fa: ImmutableArray[A], z: B)(f: (B, A) => B) =
 40        fa.foldLeft(z)(f)
 41      def foldMap[A, B](fa: ImmutableArray[A])(f: A => B)(implicit F: Monoid[B]): B = {
 42        var i = 0
 43        var b = F.zero
 44        while(i < fa.length){
 45          b = F.append(b, f(fa(i)))
 46          i += 1
 47        }
 48        b
 49      }
 50      def foldRight[A, B](fa: ImmutableArray[A], z: => B)(f: (A, => B) => B) =
 51        fa.foldRight(z)((a, b) => f(a, b))
 52      def zip[A, B](a: => ImmutableArray[A], b: => ImmutableArray[B]) = {
 53        val _a = a
 54        if(_a.isEmpty) new ImmutableArray.ofRef(Array[(A, B)]())
 55        else new ImmutableArray.ofRef((_a.iterator zip b.iterator).toArray)
 56      }
 57      override def index[A](fa: ImmutableArray[A], i: Int) =
 58        if(0 <= i && i < fa.length) Some(fa(i)) else None
 59      override def length[A](fa: ImmutableArray[A]) =
 60        fa.length
 61      override def empty[A](fa: ImmutableArray[A]) =
 62        fa.isEmpty
 63      override def all[A](fa: ImmutableArray[A])(f: A => Boolean) = {
 64        val len = fa.length
 65        @annotation.tailrec
 66        def loop(i: Int): Boolean = {
 67          if(i < len) f(fa(i)) && loop(i + 1)
 68          else true
 69        }
 70        loop(0)
 71      }
 72      override def any[A](fa: ImmutableArray[A])(f: A => Boolean) = {
 73        val len = fa.length
 74        @annotation.tailrec
 75        def loop(i: Int): Boolean = {
 76          if(i < len) f(fa(i)) || loop(i + 1)
 77          else false
 78        }
 79        loop(0)
 80      }
 81
 82    }
 83}
 84
 85object ImmutableArray extends ImmutableArrayInstances {
 86
 87  def make[A](x: AnyRef): ImmutableArray[A] = {
 88    val y = x match {
 89      case null              => null
 90      case x: Array[Byte]    => new ofByte(x)
 91      case x: Array[Short]   => new ofShort(x)
 92      case x: Array[Char]    => new ofChar(x)
 93      case x: Array[Int]     => new ofInt(x)
 94      case x: Array[Long]    => new ofLong(x)
 95      case x: Array[Float]   => new ofFloat(x)
 96      case x: Array[Double]  => new ofDouble(x)
 97      case x: Array[Boolean] => new ofBoolean(x)
 98      case x: Array[Unit]    => new ofUnit(x)
 99      case x: Array[AnyRef]  => new ofRef(x)
100      case x: String         => new StringArray(x)
101    }
102    y.asInstanceOf[ImmutableArray[A]]
103  }
104
105  /**
106   * Wrap `x` in an `ImmutableArray`.
107   *
108   * Provides better type inference than `make[A]`
109   */
110  def fromArray[A](x: Array[A]): ImmutableArray[A] = {
111    val y = x.asInstanceOf[AnyRef] match {
112      case null              => null
113      case x: Array[Byte]    => new ofByte(x)
114      case x: Array[Short]   => new ofShort(x)
115      case x: Array[Char]    => new ofChar(x)
116      case x: Array[Int]     => new ofInt(x)
117      case x: Array[Long]    => new ofLong(x)
118      case x: Array[Float]   => new ofFloat(x)
119      case x: Array[Double]  => new ofDouble(x)
120      case x: Array[Boolean] => new ofBoolean(x)
121      case x: Array[Unit]    => new ofUnit(x)
122      case _: Array[AnyRef]  => new ofRef(x.asInstanceOf[Array[AnyRef]])
123    }
124    y.asInstanceOf[ImmutableArray[A]]
125  }
126
127  /** Wrap the characters in `str` in an `ImmutableArray` */
128  def fromString(str: String): ImmutableArray[Char] = new StringArray(str)
129
130  def newBuilder[A](implicit elemTag: ClassTag[A]): Builder[A, ImmutableArray[A]] =
131    ArrayBuilder.make[A].mapResult(make(_))
132
133  def newStringArrayBuilder: Builder[Char, ImmutableArray[Char]] =
134    (new StringBuilder).mapResult(fromString(_))
135
136  sealed abstract class ImmutableArray1[+A](array: Array[A]) extends ImmutableArray[A] {
137    private[this] val arr = array.clone
138    // override def stringPrefix = "ImmutableArray"
139    // override protected[this] def newBuilder = ImmutableArray.newBuilder[A](elemTag)
140
141    def componentType: Class[_] = arr.getClass().getComponentType
142
143    def apply(idx: Int) = arr(idx)
144
145    def length = arr.length
146    def toArray[B >: A : ClassTag] = arr.clone.asInstanceOf[Array[B]]
147    def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = { arr.copyToArray(xs, start, len) }
148
149    def slice(from: Int, until: Int) = fromArray(arr.slice(from, until))
150
151    // TODO can do O(1) for primitives
152    override def ++[B >: A: ClassTag](other: ImmutableArray[B]) = {
153      val newArr = new Array(length + other.length)
154      this.copyToArray(newArr, 0, length)
155      other.copyToArray(newArr, length, other.length)
156      fromArray(newArr)
157    }
158  }
159  final class ofRef[A <: AnyRef](array: Array[A]) extends ImmutableArray1[A](array) {
160    protected[this] lazy val elemTag = ClassTag[A](componentType)
161  }
162
163  final class ofByte(array: Array[Byte]) extends ImmutableArray1[Byte](array) {
164    protected[this] def elemTag = ClassTag.Byte
165  }
166
167  final class ofShort(array: Array[Short]) extends ImmutableArray1[Short](array) {
168    protected[this] def elemTag = ClassTag.Short
169  }
170
171  final class ofChar(array: Array[Char]) extends ImmutableArray1[Char](array) {
172    protected[this] def elemTag = ClassTag.Char
173
174    // def mkString = new String(arr)
175    // TODO why can elemTag be protected, but arr can't?
176  }
177
178  final class ofInt(array: Array[Int]) extends ImmutableArray1[Int](array) {
179    protected[this] def elemTag = ClassTag.Int
180  }
181
182  final class ofLong(array: Array[Long]) extends ImmutableArray1[Long](array) {
183    protected[this] def elemTag = ClassTag.Long
184  }
185
186  final class ofFloat(array: Array[Float]) extends ImmutableArray1[Float](array) {
187    protected[this] def elemTag = ClassTag.Float
188  }
189
190  final class ofDouble(array: Array[Double]) extends ImmutableArray1[Double](array) {
191    protected[this] def elemTag = ClassTag.Double
192  }
193
194  final class ofBoolean(array: Array[Boolean]) extends ImmutableArray1[Boolean](array) {
195    protected[this] def elemTag = ClassTag.Boolean
196  }
197
198  final class ofUnit(array: Array[Unit]) extends ImmutableArray1[Unit](array) {
199    protected[this] def elemTag = ClassTag.Unit
200  }
201
202  final class StringArray(val str: String) extends ImmutableArray[Char] {
203    protected[this] def elemTag = ClassTag.Char
204
205    // override protected[this] def newBuilder = (new StringBuilder).mapResult(new StringArray(_))
206
207    def apply(idx: Int) = str(idx)
208
209    def length = str.length
210    def toArray[B >: Char : ClassTag] = str.toArray
211    def copyToArray[B >: Char](xs: Array[B], start: Int, len: Int): Unit = {
212      xs match {
213        case xs0: Array[Char] =>
214          str.copyToArray(xs0, start, len)
215        case _ =>
216          str.toCharArray.copyToArray(xs, start, len)
217      }
218    }
219
220    def slice(from: Int, until: Int) = new StringArray(str.slice(from, until))
221
222    def ++[B >: Char: ClassTag](other: ImmutableArray[B]) =
223      other match {
224        case other: StringArray => new StringArray(str + other.str)
225        case _ => {
226          val newArr = new Array[B](length + other.length)
227          this.copyToArray(newArr, 0, length)
228          other.copyToArray(newArr, length, other.length)
229          fromArray(newArr)
230        }
231      }
232  }
233
234  implicit def wrapArray[A](immArray: ImmutableArray[A]): WrappedImmutableArray[A] = {
235    import ImmutableArray.{WrappedImmutableArray => IAO}
236    immArray match {
237      case a: StringArray => new IAO.ofStringArray(a)
238      case a: ofRef[_] => new IAO.ofRef(a)
239      case a: ofByte => new IAO.ofByte(a)
240      case a: ofShort => new IAO.ofShort(a)
241      case a: ofChar => new IAO.ofChar(a)
242      case a: ofInt => new IAO.ofInt(a)
243      case a: ofLong => new IAO.ofLong(a)
244      case a: ofFloat => new IAO.ofFloat(a)
245      case a: ofDouble => new IAO.ofDouble(a)
246      case a: ofBoolean => new IAO.ofBoolean(a)
247      case a: ofUnit => new IAO.ofUnit(a)
248    }
249  }
250
251  implicit def unwrapArray[A](immArrayOps: WrappedImmutableArray[A]): ImmutableArray[A] = immArrayOps.value
252
253  abstract class WrappedImmutableArray[+A](val value: ImmutableArray[A]) extends
254          IndexedSeq[A] {
255    def apply(index: Int) = value(index)
256    def length = value.length
257
258    protected[this] def arrayBuilder: Builder[A, ImmutableArray[A]]
259  }
260
261  object WrappedImmutableArray {
262    import scalaz.{ImmutableArray => IA}
263    class ofStringArray(val strArray: StringArray) extends WrappedImmutableArray[Char](strArray) {
264      override protected[this] def arrayBuilder = (new StringBuilder).mapResult(str => new StringArray(str.toString))
265    }
266
267    abstract class ofImmutableArray1[+A](val immArray: ImmutableArray1[A]) extends WrappedImmutableArray[A](immArray) {
268      protected[this] def elemTag: ClassTag[A]
269
270      override protected[this] def arrayBuilder = ImmutableArray.newBuilder[A](elemTag)
271    }
272
273    final class ofRef[+A <: AnyRef](array: IA.ofRef[A]) extends ofImmutableArray1[A](array) {
274      protected[this] lazy val elemTag = ClassTag[A](array.componentType)
275    }
276
277    final class ofByte(array: IA.ofByte) extends ofImmutableArray1[Byte](array) {
278      protected[this] def elemTag = ClassTag.Byte
279    }
280
281    final class ofShort(array: IA.ofShort) extends ofImmutableArray1[Short](array) {
282      protected[this] def elemTag = ClassTag.Short
283    }
284
285    final class ofChar(array: IA.ofChar) extends ofImmutableArray1[Char](array) {
286      protected[this] def elemTag = ClassTag.Char
287    }
288
289    final class ofInt(array: IA.ofInt) extends ofImmutableArray1[Int](array) {
290      protected[this] def elemTag = ClassTag.Int
291    }
292
293    final class ofLong(array: IA.ofLong) extends ofImmutableArray1[Long](array) {
294      protected[this] def elemTag = ClassTag.Long
295    }
296
297    final class ofFloat(array: IA.ofFloat) extends ofImmutableArray1[Float](array) {
298      protected[this] def elemTag = ClassTag.Float
299    }
300
301    final class ofDouble(array: IA.ofDouble) extends ofImmutableArray1[Double](array) {
302      protected[this] def elemTag = ClassTag.Double
303    }
304
305    final class ofBoolean(array: IA.ofBoolean) extends ofImmutableArray1[Boolean](array) {
306      protected[this] def elemTag = ClassTag.Boolean
307    }
308
309    final class ofUnit(array: IA.ofUnit) extends ofImmutableArray1[Unit](array) {
310      protected[this] def elemTag = ClassTag.Unit
311    }
312  }
313
314  sealed class ImmutableArrayCharW(val self: ImmutableArray[Char]) extends Ops[ImmutableArray[Char]] {
315    def asString: String = self match {
316      case a: StringArray => a.str
317      case a: ofChar => wrapArray(a).mkString
318      case _ => sys.error("Unknown subtype of ImmutableArray[Char]")
319    }
320  }
321
322  implicit def wrapRopeChar(array: ImmutableArray[Char]): ImmutableArrayCharW = new ImmutableArrayCharW(array)
323}