summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/mutable/ArrayOps.scala
blob: 5de3dad256d85e4d15362722d21c79bba89630b7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2002-2013, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

package scala
package collection
package mutable

import java.util

import scala.reflect.ClassTag
import parallel.mutable.ParArray

/** This class serves as a wrapper for `Array`s with all the operations found in
 *  indexed sequences. Where needed, instances of arrays are implicitly converted
 *  into this class.
 *
 *  The difference between this class and `WrappedArray` is that calling transformer
 *  methods such as `filter` and `map` will yield an array, whereas a `WrappedArray`
 *  will remain a `WrappedArray`.
 *
 *  @since 2.8
 *
 *  @tparam T   type of the elements contained in this array.
 *
 *  @define Coll `Array`
 *  @define orderDependent
 *  @define orderDependentFold
 *  @define mayNotTerminateInf
 *  @define willNotTerminateInf
 */
sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {

  private def elementClass: Class[_] =
    repr.getClass.getComponentType

  override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) {
    val l = len min repr.length min (xs.length - start)
    if (l > 0) Array.copy(repr, 0, xs, start, l)
  }

  override def slice(from: Int, until: Int): Array[T] = {
     val lo = math.max(from, 0)
     val hi = math.min(math.max(until, 0), repr.length)
     val size = math.max(hi - lo, 0)
     val result = java.lang.reflect.Array.newInstance(elementClass, size)
     if (size > 0) {
      Array.copy(repr, lo, result, 0, size)
     }
     result.asInstanceOf[Array[T]]
  }

  override def toArray[U >: T : ClassTag]: Array[U] = {
    val thatElementClass = implicitly[ClassTag[U]].runtimeClass
    if (elementClass eq thatElementClass)
      repr.asInstanceOf[Array[U]]
    else
      super.toArray[U]
  }

  def :+[B >: T: ClassTag](elem: B): Array[B] = {
    val result = Array.ofDim[B](repr.length + 1)
    Array.copy(repr, 0, result, 0, repr.length)
    result(repr.length) = elem
    result
  }

  def +:[B >: T: ClassTag](elem: B): Array[B] = {
    val result = Array.ofDim[B](repr.length + 1)
    result(0) = elem
    Array.copy(repr, 0, result, 1, repr.length)
    result
  }

  override def par = ParArray.handoff(repr)

  /** Flattens a two-dimensional array by concatenating all its rows
   *  into a single array.
   *
   *  @tparam U        Type of row elements.
   *  @param asTrav    A function that converts elements of this array to rows - arrays of type `U`.
   *  @return          An array obtained by concatenating rows of this array.
   */
  def flatten[U](implicit asTrav: T => scala.collection.Traversable[U], m: ClassTag[U]): Array[U] = {
    val b = Array.newBuilder[U]
    b.sizeHint(map{case is: scala.collection.IndexedSeq[_] => is.size case _ => 0}.sum)
    for (xs <- this)
      b ++= asTrav(xs)
    b.result()
  }

  /** Transposes a two dimensional array.
   *
   *  @tparam U       Type of row elements.
   *  @param asArray  A function that converts elements of this array to rows - arrays of type `U`.
   *  @return         An array obtained by replacing elements of this arrays with rows the represent.
   */
  def transpose[U](implicit asArray: T => Array[U]): Array[Array[U]] = {
    val bb: Builder[Array[U], Array[Array[U]]] = Array.newBuilder(ClassTag[Array[U]](elementClass))
    if (isEmpty) bb.result()
    else {
      def mkRowBuilder() = Array.newBuilder(ClassTag[U](elementClass.getComponentType))
      val bs = asArray(head) map (_ => mkRowBuilder())
      for (xs <- this) {
        var i = 0
        for (x <- asArray(xs)) {
          bs(i) += x
          i += 1
        }
      }
      for (b <- bs) bb += b.result()
      bb.result()
    }
  }

  /** Converts an array of pairs into an array of first elements and an array of second elements.
   *
   *  @tparam T1    the type of the first half of the element pairs
   *  @tparam T2    the type of the second half of the element pairs
   *  @param asPair an implicit conversion which asserts that the element type
   *                of this Array is a pair.
   *  @param ct1    a class tag for T1 type parameter that is required to create an instance
   *                of Array[T1]
   *  @param ct2    a class tag for T2 type parameter that is required to create an instance
   *                of Array[T2]
   *  @return       a pair of Arrays, containing, respectively, the first and second half
   *                of each element pair of this Array.
   */
  // implementation NOTE: ct1 and ct2 can't be written as context bounds because desugared
  // implicits are put in front of asPair parameter that is supposed to guide type inference
  def unzip[T1, T2](implicit asPair: T => (T1, T2), ct1: ClassTag[T1], ct2: ClassTag[T2]): (Array[T1], Array[T2]) = {
    val a1 = new Array[T1](length)
    val a2 = new Array[T2](length)
    var i = 0
    while (i < length) {
      val e = apply(i)
      a1(i) = e._1
      a2(i) = e._2
      i += 1
    }
    (a1, a2)
  }

  /** Converts an array of triples into three arrays, one containing the elements from each position of the triple.
   *
   *  @tparam T1      the type of the first of three elements in the triple
   *  @tparam T2      the type of the second of three elements in the triple
   *  @tparam T3      the type of the third of three elements in the triple
   *  @param asTriple an implicit conversion which asserts that the element type
   *                  of this Array is a triple.
   *  @param ct1    a class tag for T1 type parameter that is required to create an instance
   *                of Array[T1]
   *  @param ct2    a class tag for T2 type parameter that is required to create an instance
   *                of Array[T2]
   *  @param ct3    a class tag for T3 type parameter that is required to create an instance
   *                of Array[T3]
   *  @return         a triple of Arrays, containing, respectively, the first, second, and third
   *                  elements from each element triple of this Array.
   */
  // implementation NOTE: ct1, ct2, ct3 can't be written as context bounds because desugared
  // implicits are put in front of asPair parameter that is supposed to guide type inference
  def unzip3[T1, T2, T3](implicit asTriple: T => (T1, T2, T3), ct1: ClassTag[T1], ct2: ClassTag[T2],
    ct3: ClassTag[T3]): (Array[T1], Array[T2], Array[T3]) = {
    val a1 = new Array[T1](length)
    val a2 = new Array[T2](length)
    val a3 = new Array[T3](length)
    var i = 0
    while (i < length) {
      val e = apply(i)
      a1(i) = e._1
      a2(i) = e._2
      a3(i) = e._3
      i += 1
    }
    (a1, a2, a3)
  }

  def seq = thisCollection
}

/** to provide binary compat for 2.11 and 2.12 this class contains
  * functionality that should be migrated to ArrayOps in 2.13
  *
  */
private[mutable] sealed trait ArrayOpsImpl[T] extends Any with ArrayOps[T] {
  override final def slice(from: Int, until: Int): Array[T] = {
    val start = if (from < 0) 0 else from
    if (until <= start || start >= repr.length)
      return emptyImpl
    val end = if (until > length) length else until
    sliceImpl(start, end)
  }
  protected def emptyImpl: Array[T]
  protected def sliceImpl(from: Int, until: Int): Array[T]

}

/**
 * A companion object for `ArrayOps`.
 *
 * @since 2.8
 */
object ArrayOps {

  private val emptyByteArray = new Array[Byte](0)
  private val emptyShortArray = new Array[Short](0)
  private val emptyIntArray = new Array[Int](0)
  private val emptyLongArray = new Array[Long](0)
  private val emptyFloatArray = new Array[Float](0)
  private val emptyDoubleArray = new Array[Double](0)
  private val emptyUnitArray = new Array[Unit](0)
  private val emptyCharArray = new Array[Char](0)
  private val emptyBooleanArray = new Array[Boolean](0)

  /** A subclass of `ArrayOps` for arrays containing reference types. */
  final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOpsImpl[T] with ArrayLike[T, Array[T]] {

    override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr)
    override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](repr.getClass.getComponentType))
    protected override def emptyImpl:Array[T] = util.Arrays.copyOf[T](repr,0)
    protected override def sliceImpl(from: Int, until: Int): Array[T] = util.Arrays.copyOfRange[T](repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): T = repr(index)
    def update(index: Int, elem: T) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Byte`s. */
  final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOpsImpl[Byte] with ArrayLike[Byte, Array[Byte]] {

    override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr)
    override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofByte
    protected override def emptyImpl = emptyByteArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Byte = repr(index)
    def update(index: Int, elem: Byte) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Short`s. */
  final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOpsImpl[Short] with ArrayLike[Short, Array[Short]] {

    override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr)
    override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofShort
    protected override def emptyImpl = emptyShortArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Short = repr(index)
    def update(index: Int, elem: Short) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Char`s. */
  final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOpsImpl[Char] with ArrayLike[Char, Array[Char]] {

    override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr)
    override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofChar
    protected override def emptyImpl = emptyCharArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Char = repr(index)
    def update(index: Int, elem: Char) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Int`s. */
  final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOpsImpl[Int] with ArrayLike[Int, Array[Int]] {

    override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr)
    override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofInt
    protected override def emptyImpl = emptyIntArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Int = repr(index)
    def update(index: Int, elem: Int) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Long`s. */
  final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOpsImpl[Long] with ArrayLike[Long, Array[Long]] {

    override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr)
    override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofLong
    protected override def emptyImpl = emptyLongArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Long = repr(index)
    def update(index: Int, elem: Long) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Float`s. */
  final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOpsImpl[Float] with ArrayLike[Float, Array[Float]] {

    override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr)
    override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofFloat
    protected override def emptyImpl = emptyFloatArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Float = repr(index)
    def update(index: Int, elem: Float) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Double`s. */
  final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOpsImpl[Double] with ArrayLike[Double, Array[Double]] {

    override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr)
    override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofDouble
    protected override def emptyImpl = emptyDoubleArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Double = repr(index)
    def update(index: Int, elem: Double) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays containing `Boolean`s. */
  final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOpsImpl[Boolean] with ArrayLike[Boolean, Array[Boolean]] {

    override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr)
    override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofBoolean
    protected override def emptyImpl = emptyBooleanArray
    protected override def sliceImpl(from: Int, until: Int) = util.Arrays.copyOfRange(repr, from, until)

    def length: Int = repr.length
    def apply(index: Int): Boolean = repr(index)
    def update(index: Int, elem: Boolean) { repr(index) = elem }
  }

  /** A subclass of `ArrayOps` for arrays of `Unit` types. */
  final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOpsImpl[Unit] with ArrayLike[Unit, Array[Unit]] {

    override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
    override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr)
    override protected[this] def newBuilder = new ArrayBuilder.ofUnit
    protected override def emptyImpl = emptyUnitArray
    protected override def sliceImpl(from: Int, until: Int) = {
      // cant use util.Arrays.copyOfRange[Unit](repr, from, until) - Unit is special and doesnt compile
      val res = new Array[Unit](until-from)
      System.arraycopy(repr, from, res, 0, res.size)
      res
    }

    def length: Int = repr.length
    def apply(index: Int): Unit = repr(index)
    def update(index: Int, elem: Unit) { repr(index) = elem }
  }
}