8000 Array slice optimisations by mkeskells · Pull Request #5652 · scala/scala · GitHub
[go: up one dir, main page]

Skip to content

Array slice optimisations #5652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
add optimisations to ArrayOps and WrappedArray to use Array block cop…
…y operations rather than builder/iterator for slace and take
  • Loading branch information
mkeskells authored and rorygraves committed Jan 26, 2017
commit 51a3f22d301783c9c8200e1df18e9eb3332415af
74 changes: 64 additions & 10 deletions src/library/scala/collection/mutable/ArrayOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ package scala
package collection
package mutable

import java.util

import scala.compat.Platform.arraycopy
import scala.reflect.ClassTag
import scala.runtime.ScalaRunTime._
Expand Down Expand Up @@ -175,127 +177,179 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza

}

/** 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 class of `ArrayOps` for arrays containing reference types. */
final class ofRef[T <: AnyRef](override val repr: Array[T]) extends AnyVal with ArrayOps[T] with ArrayLike[T, Array[T]] {
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](arrayElementClass(repr.getClass)))
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 class of `ArrayOps` for arrays containing `byte`s. */
final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] {
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 class of `ArrayOps` for arrays containing `short`s. */
final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] {
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 class of `ArrayOps` for arrays containing `char`s. */
final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] {
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 class of `ArrayOps` for arrays containing `int`s. */
final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] {
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 class of `ArrayOps` for arrays containing `long`s. */
final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] {
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 class of `ArrayOps` for arrays containing `float`s. */
final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] {
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 class of `ArrayOps` for arrays containing `double`s. */
final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] {
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 class of `ArrayOps` for arrays containing `boolean`s. */
final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] {
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
< 8000 /td> def apply(index: Int): Boolean = repr(index)
def update(index: Int, elem: Boolean) { repr(index) = elem }
}

/** A class of `ArrayOps` for arrays of `Unit` types. */
final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] {
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)
Expand Down
49 changes: 49 additions & 0 deletions src/library/scala/collection/mutable/WrappedArray.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ extends AbstractSeq[T]
else
super.toArray[U]
}
override def slice(from: Int, until: Int): WrappedArray[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)
}
//retain existing functionallity for existing implementations outside this file
protected def emptyImpl: WrappedArray[T] = newBuilder.result()
//retain existing functionallity for existing implementations outside this file
protected def sliceImpl(from: Int, until: Int): WrappedArray[T] = super.slice(from, until)

override def stringPrefix = "WrappedArray"

Expand All @@ -88,6 +99,7 @@ extends AbstractSeq[T]
/** A companion object used to create instances of `WrappedArray`.
*/
object WrappedArray {
import java.util
// This is reused for all calls to empty.
private val EmptyWrappedArray = new ofRef[AnyRef](new Array[AnyRef](0))
def empty[T <: AnyRef]: WrappedArray[T] = EmptyWrappedArray.asInstanceOf[WrappedArray[T]]
Expand Down Expand Up @@ -121,73 +133,110 @@ object WrappedArray {

def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer

private val emptyWrappedByte = new ofByte(new Array[Byte](0))
private val emptyWrappedShort = new ofShort(new Array[Short](0))
private val emptyWrappedInt = new ofInt(new Array[Int](0))
private val emptyWrappedLong = new ofLong(new Array[Long](0))
private val emptyWrappedFloat = new ofFloat(new Array[Float](0))
private val emptyWrappedDouble = new ofDouble(new Array[Double](0))
private val emptyWrappedUnit = new ofUnit(new Array[Unit](0))
private val emptyWrappedChar = new ofChar(new Array[Char](0))
private val emptyWrappedBoolean = new ofBoolean(new Array[Boolean](0))

final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable {
lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass))
def length: Int = array.length
def apply(index: Int): T = array(index).asInstanceOf[T]
def update(index: Int, elem: T) { array(index) = elem }
protected override def emptyImpl = new ofRef(util.Arrays.copyOf[T](array,0))
protected override def sliceImpl(from: Int, until: Int) = new ofRef[T](util.Arrays.copyOfRange[T](array, from, until))
}

final class ofByte(val array: Array[Byte]) extends WrappedArray[Byte] with Serializable {
def elemTag = ClassTag.Byte
def length: Int = array.length
def apply(index: Int): Byte = array(index)
def update(index: Int, elem: Byte) { array(index) = elem }
protected override def emptyImpl = emptyWrappedByte
protected override def sliceImpl(from: Int, until: Int) = new ofByte(util.Arrays.copyOfRange(array, from, until))
}

final class ofShort(val array: Array[Short]) extends WrappedArray[Short] with Serializable {
def elemTag = ClassTag.Short
def length: Int = array.length
def apply(index: Int): Short = array(index)
def update(index: Int, elem: Short) { array(index) = elem }
protected override def emptyImpl = emptyWrappedShort
protected override def sliceImpl(from: Int, until: Int) = new ofShort(util.Arrays.copyOfRange(array, from, until))
}

final class ofChar(val array: Array[Char]) extends WrappedArray[Char] with Serializable {
def elemTag = ClassTag.Char
def length: Int = array.length
def apply(index: Int): Char = array(index)
def update(index: Int, elem: Char) { array(index) = elem }
protected override def emptyImpl = emptyWrappedChar
protected override def sliceImpl(from: Int, until: Int) = new ofChar(util.Arrays.copyOfRange(array, from, until))
}

final class ofInt(val array: Array[Int]) extends WrappedArray[Int] with Serializable {
def elemTag = ClassTag.Int
def length: Int = array.length
def apply(index: Int): Int = array(index)
def update(index: Int, elem: Int) { array(index) = elem }
protected override def emptyImpl = emptyWrappedInt
protected override def sliceImpl(from: Int, until: Int) = new ofInt(util.Arrays.copyOfRange(array, from, until))
}

final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable {
def elemTag = ClassTag.Long
def length: Int = array.length
def apply(index: Int): Long = array(index)
def update(index: Int, elem: Long) { array(index) = elem }
protected override def emptyImpl = emptyWrappedLong
protected override def sliceImpl(from: Int, until: Int) = new ofLong(util.Arrays.copyOfRange(array, from, until))
}

final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable {
def elemTag = ClassTag.Float
def length: Int = array.length
def apply(index: Int): Float = array(index)
def update(index: Int, elem: Float) { array(index) = elem }
protected override def emptyImpl = emptyWrappedFloat
protected override def sliceImpl(from: Int, until: Int) = new ofFloat(util.Arrays.copyOfRange(array, from, until))
}

final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable {
def elemTag = ClassTag.Double
def length: Int = array.length
def apply(index: Int): Double = array(index)
def update(index: Int, elem: Double) { array(index) = elem }
protected override def emptyImpl = emptyWrappedDouble
protected override def sliceImpl(from: Int, until: Int) = new ofDouble(util.Arrays.copyOfRange(array, from, until))
}

final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable {
def elemTag = ClassTag.Boolean
def length: Int = array.length
def apply(index: Int): Boolean = array(index)
def update(index: Int, elem: Boolean) { array(index) = elem }
protected override def emptyImpl = emptyWrappedBoolean
protected override def sliceImpl(from: Int, until: Int) = new ofBoolean(util.Arrays.copyOfRange(array, from, until))
}

final class ofUnit(val array: Array[Unit]) extends WrappedArray[Unit] with Serializable {
def elemTag = ClassTag.Unit
def length: Int = array.length
def apply(index: Int): Unit = array(index)
def update(index: Int, elem: Unit) { array(index) = elem }
protected override def emptyImpl = emptyWrappedUnit
protected override def sliceImpl(from: Int, until: Int) = {
// cant use
// new ofUnit(util.Arrays.copyOfRange[Unit](array, from, until)) - Unit is special and doesnt compile
// 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, until-from)
new ofUnit(res)
}
}
}
0