diff options
Diffstat (limited to 'library/src/main/scala/scala/scalajs/js/typedarray')
15 files changed, 552 insertions, 0 deletions
diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBuffer.scala b/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBuffer.scala new file mode 100644 index 0000000..b8b8160 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBuffer.scala @@ -0,0 +1,17 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class ArrayBuffer(length: Int) extends js.Object { + + /** Length of this buffer in bytes */ + val byteLength: Int = js.native + + /** Returns a copy of the given slice of this array buffer */ + def slice(begin: Int, end: Int = ???): ArrayBuffer = js.native + + // Note: Some specifications specify a static isView method on ArrayBuffer + // that checks whether a given object is an ArrayBufferView. We omit it here + // since neither Node.js nor PhantomJS support it at the time of writing. + +} diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBufferInputStream.scala b/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBufferInputStream.scala new file mode 100644 index 0000000..f3d2afb --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBufferInputStream.scala @@ -0,0 +1,88 @@ +package scala.scalajs.js.typedarray + +import java.io.InputStream + +/** A java.io.InputStream wrapping a JavaScript ArrayBuffer + * + * This class is extremely similar to a ByteArrayInputStream, but + * uses ArrayBuffers as the underlying representation. Stream + * implementations may special case on this stream for better + * performance and access the underlying buffer directly. (They still + * need to make sure the internal pointers are properly aligned + * though). + * + * This stream has several public members (n.b. [[buffer]], [[offset]], + * [[length]] and [[pos]]) in order to allow JavaScript aware applications to + * special case on this kind of stream and access the underlying + * [[ArrayBuffer]] directly for efficiency. In this case it is the client's + * responsibility to synchronize [[pos]], as if the stream were read normally + * (if the context in which it is used requires this). + * + * @param buffer Underlying ArrayBuffer + * @param offset Offset in bytes in [[buffer]] + * @param length Length in bytes in [[buffer]] + */ +class ArrayBufferInputStream(val buffer: ArrayBuffer, val offset: Int, + val length: Int) extends InputStream { + + /** Convenience constructor. Strictly equivalent to + * {{new ArrayBufferInputStream(buffer, 0, buffer.byteLength)} + */ + def this(buffer: ArrayBuffer) = this(buffer, 0, buffer.byteLength) + + private val uintView = new Uint8Array(buffer, offset, length) + private val byteView = new Int8Array(buffer, offset, length) + + /** Used to persist [[pos]] when mark is called */ + protected var mark: Int = 0 + + /** Next byte to read in the buffer (after adding offset). + * + * Use [[skip]] to update (protects from overrun and moving backwards). + */ + @inline def pos: Int = _pos + @inline protected def pos_=(x: Int): Unit = _pos = x + private[this] var _pos: Int = 0 + + override def available(): Int = length - pos + override def mark(readlimit: Int): Unit = { mark = pos } + override def markSupported(): Boolean = true + def read(): Int = { + if (pos < length) { + val res = uintView(pos) + pos += 1 + res + } else -1 + } + + override def read(b: Array[Byte], off: Int, reqLen: Int): Int = { + if (off < 0 || reqLen < 0 || reqLen > b.length - off) + throw new IndexOutOfBoundsException + + val len = Math.min(reqLen, length - pos) + + if (reqLen == 0) + 0 // 0 requested, 0 returned + else if (len == 0) + -1 // nothing to read at all + else { + var i = 0 + while (i < len) { + b(i + off) = byteView(pos + i) + i += 1 + } + pos += len + len + } + } + + override def reset(): Unit = { pos = mark } + + /** Skips a given number of bytes. Always skips the maximum number possible */ + override def skip(n: Long): Long = { + val k = Math.max(0, Math.min(n, length - pos)).toInt + pos += k + k.toLong + } + +} diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBufferView.scala b/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBufferView.scala new file mode 100644 index 0000000..6b25bf5 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/ArrayBufferView.scala @@ -0,0 +1,14 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +trait ArrayBufferView extends js.Object { + /** The underlying buffer of this ArrayBufferView */ + val buffer: ArrayBuffer = js.native + + /** The number of bytes of this ArrayBufferView */ + val byteLength: Int = js.native + + /** The offset of this ArrayBufferView in the underlying buffer */ + val byteOffset: Int = js.native +} diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/DataView.scala b/library/src/main/scala/scala/scalajs/js/typedarray/DataView.scala new file mode 100644 index 0000000..d97544c --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/DataView.scala @@ -0,0 +1,26 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class DataView(buffer: ArrayBuffer, byteOffset: Int = 0, + byteLength: Int = ???) extends ArrayBufferView { + + def getInt8(byteOffset: Int): Byte = js.native + def getUint8(byteOffset: Int): Short = js.native + def getInt16(byteOffset: Int, littleEndian: Boolean = false): Short = js.native + def getUint16(byteOffset: Int, littleEndian: Boolean = false): Int = js.native + def getInt32(byteOffset: Int, littleEndian: Boolean = false): Int = js.native + def getUint32(byteOffset: Int, littleEndian: Boolean = false): Double = js.native + def getFloat32(byteOffset: Int, littleEndian: Boolean = false): Float = js.native + def getFloat64(byteOffset: Int, littleEndian: Boolean = false): Double = js.native + + def setInt8(byteOffset: Int, value: Byte): Unit = js.native + def setUint8(byteOffset: Int, value: Short): Unit = js.native + def setInt16(byteOffset: Int, value: Short, littleEndian: Boolean = false): Unit = js.native + def setUint16(byteOffset: Int, value: Int, littleEndian: Boolean = false): Unit = js.native + def setInt32(byteOffset: Int, value: Int, littleEndian: Boolean = false): Unit = js.native + def setUint32(byteOffset: Int, value: Double, littleEndian: Boolean = false): Unit = js.native + def setFloat32(byteOffset: Int, value: Float, littleEndian: Boolean = false): Unit = js.native + def setFloat64(byteOffset: Int, value: Double, littleEndian: Boolean = false): Unit = js.native + +} diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Float32Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Float32Array.scala new file mode 100644 index 0000000..abb0dd9 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Float32Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Float32Array private extends TypedArray[Float, Float32Array] { + + /** Constructs a Float32Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Float32Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Float32Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Float32Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Float32Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Float64Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Float64Array.scala new file mode 100644 index 0000000..526b376 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Float64Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Float64Array private extends TypedArray[Double, Float64Array] { + + /** Constructs a Float64Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Float64Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Float64Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Float64Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Float64Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Int16Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Int16Array.scala new file mode 100644 index 0000000..c71f101 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Int16Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Int16Array private extends TypedArray[Short, Int16Array] { + + /** Constructs a Int16Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Int16Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Int16Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Int16Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Int16Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Int32Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Int32Array.scala new file mode 100644 index 0000000..37208e9 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Int32Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Int32Array private extends TypedArray[Int, Int32Array] { + + /** Constructs a Int32Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Int32Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Int32Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Int32Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Int32Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Int8Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Int8Array.scala new file mode 100644 index 0000000..690ff07 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Int8Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Int8Array private extends TypedArray[Byte, Int8Array] { + + /** Constructs a Int8Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Int8Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Int8Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Int8Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Int8Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/TypedArray.scala b/library/src/main/scala/scala/scalajs/js/typedarray/TypedArray.scala new file mode 100644 index 0000000..4e33b5d --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/TypedArray.scala @@ -0,0 +1,46 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSBracketAccess + +trait TypedArray[T, Repr] extends ArrayBufferView { + + /** The number of elements in this TypedArray */ + val length: Int = js.native + + /** Retrieve element at index */ + @JSBracketAccess + def apply(index: Int): T = js.native + + /** Set element at index */ + @JSBracketAccess + def update(index: Int, value: T): Unit = js.native + + /** Retrieve element at index */ + @JSBracketAccess + def get(index: Int): T = js.native + + /** Set element at index */ + @JSBracketAccess + def set(index: Int, value: T): Unit = js.native + + /** Set the values of typedArray in this TypedArray */ + def set(typedArray: TypedArray[_, _]): Unit = js.native + + /** Set the values of typedArray in this TypedArray at given offset */ + def set(typedArray: TypedArray[_, _], offset: Int): Unit = js.native + + /** Set the values from array in this TypedArray */ + def set(array: js.Array[_]): Unit = js.native + + /** Set the values from array in this TypedArray at given offset */ + def set(array: js.Array[_], offset: Int): Unit = js.native + + /** Create a new TypedArray view of this TypedArray at given location */ + def subarray(begin: Int, end: Int = ???): Repr = js.native + +} + +trait TypedArrayStatic extends js.Object { + val BYTES_PER_ELEMENT: Int = js.native +} diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Uint16Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Uint16Array.scala new file mode 100644 index 0000000..82d2847 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Uint16Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Uint16Array private extends TypedArray[Int, Uint16Array] { + + /** Constructs a Uint16Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Uint16Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Uint16Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Uint16Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Uint16Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Uint32Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Uint32Array.scala new file mode 100644 index 0000000..9742e19 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Uint32Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Uint32Array private extends TypedArray[Double, Uint32Array] { + + /** Constructs a Uint32Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Uint32Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Uint32Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Uint32Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Uint32Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Uint8Array.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Uint8Array.scala new file mode 100644 index 0000000..f54904c --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Uint8Array.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Uint8Array private extends TypedArray[Short, Uint8Array] { + + /** Constructs a Uint8Array with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Uint8Array with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Uint8Array with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Uint8Array view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Uint8Array extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/Uint8ClampedArray.scala b/library/src/main/scala/scala/scalajs/js/typedarray/Uint8ClampedArray.scala new file mode 100644 index 0000000..601d65c --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/Uint8ClampedArray.scala @@ -0,0 +1,24 @@ +package scala.scalajs.js.typedarray + +import scala.scalajs.js + +class Uint8ClampedArray private extends TypedArray[Int, Uint8ClampedArray] { + + /** Constructs a Uint8ClampedArray with the given length. Initialized to all 0 */ + def this(length: Int) = this() + + /** Creates a new Uint8ClampedArray with the same elements than the given TypedArray + * + * The elements are converted before being stored in the new Int8Array. + */ + def this(typedArray: TypedArray[_, _]) = this() + + /** Creates a new Uint8ClampedArray with the elements in the given array */ + def this(array: js.Array[_]) = this() + + /** Creates a Uint8ClampedArray view on the given ArrayBuffer */ + def this(buffer: ArrayBuffer, byteOffset: Int = 0, length: Int = ???) = this() + +} + +object Uint8ClampedArray extends TypedArrayStatic diff --git a/library/src/main/scala/scala/scalajs/js/typedarray/package.scala b/library/src/main/scala/scala/scalajs/js/typedarray/package.scala new file mode 100644 index 0000000..0ab5a05 --- /dev/null +++ b/library/src/main/scala/scala/scalajs/js/typedarray/package.scala @@ -0,0 +1,145 @@ +package scala.scalajs.js + +import JSConverters._ + +/** The typdearray package provides facade types for JavaScript + * ArrayBuffer, TypeArrays and DataView. Further, it provides + * conversions between primitive Scala arrays and TypedArrays + */ +package object typedarray { + + // Implicit classes scala.Array -> TypedArray + implicit class AB2TA(val array: scala.Array[Byte]) extends AnyVal { + def toTypedArray: Int8Array = byteArray2Int8Array(array) + } + + implicit class AS2TA(val array: scala.Array[Short]) extends AnyVal { + def toTypedArray: Int16Array = shortArray2Int16Array(array) + } + + implicit class AC2TA(val array: scala.Array[Char]) extends AnyVal { + def toTypedArray: Uint16Array = charArray2Uint16Array(array) + } + + implicit class AI2TA(val array: scala.Array[Int]) extends AnyVal { + def toTypedArray: Int32Array = intArray2Int32Array(array) + } + + implicit class AF2TA(val array: scala.Array[Float]) extends AnyVal { + def toTypedArray: Float32Array = floatArray2Float32Array(array) + } + + implicit class AD2TA(val array: scala.Array[Double]) extends AnyVal { + def toTypedArray: Float64Array = doubleArray2Float64Array(array) + } + + // Implicit classes TypedArray -> scala.Array + implicit class TA2AB(val array: Int8Array) extends AnyVal { + def toArray: scala.Array[Byte] = int8Array2ByteArray(array) + } + + implicit class TA2AS(val array: Int16Array) extends AnyVal { + def toArray: scala.Array[Short] = int16Array2ShortArray(array) + } + + implicit class TA2AC(val array: Uint16Array) extends AnyVal { + def toArray: scala.Array[Char] = uint16Array2CharArray(array) + } + + implicit class TA2AI(val array: Int32Array) extends AnyVal { + def toArray: scala.Array[Int] = int32Array2IntArray(array) + } + + implicit class TA2AF(val array: Float32Array) extends AnyVal { + def toArray: scala.Array[Float] = float32Array2FloatArray(array) + } + + implicit class TA2AD(val array: Float64Array) extends AnyVal { + def toArray: scala.Array[Double] = float64Array2DoubleArray(array) + } + + // scala.Array -> TypedArray + + def byteArray2Int8Array(array: scala.Array[Byte]): Int8Array = + array2typedArrayImpl(array, new Int8Array(array.length)) + + def shortArray2Int16Array(array: scala.Array[Short]): Int16Array = + array2typedArrayImpl(array, new Int16Array(array.length)) + + def charArray2Uint16Array(array: scala.Array[Char]): Uint16Array = { + // Can't use array2typedArrayImpl because Uint16Array contains Ints + val len = array.length + val dest = new Uint16Array(len) + var i = 0 + while (i < len) { + dest(i) = array(i).toInt + i += 1 + } + dest + } + + def intArray2Int32Array(array: scala.Array[Int]): Int32Array = + array2typedArrayImpl(array, new Int32Array(array.length)) + + def floatArray2Float32Array(array: scala.Array[Float]): Float32Array = + array2typedArrayImpl(array, new Float32Array(array.length)) + + def doubleArray2Float64Array(array: scala.Array[Double]): Float64Array = + array2typedArrayImpl(array, new Float64Array(array.length)) + + @inline private def array2typedArrayImpl[ + @specialized(Byte, Short, Int, Float, Double) T, + Repr <: TypedArray[T, Repr]]( + array: scala.Array[T], dest: Repr): Repr = { + val len = array.length + var i = 0 + while (i < len) { + dest(i) = array(i) + i += 1 + } + dest + } + + // TypedArray -> scala.Array + + def int8Array2ByteArray(array: Int8Array): scala.Array[Byte] = + typedArray2arrayImpl(array, new scala.Array(array.length)) + + def int16Array2ShortArray(array: Int16Array): scala.Array[Short] = + typedArray2arrayImpl(array, new scala.Array(array.length)) + + def uint16Array2CharArray(array: Uint16Array): scala.Array[Char] = { + // Can't use typedArray2arrayImpl because Uint16Array contains Ints + val len = array.length + val dest = new scala.Array[Char](len) + var i = 0 + while (i < len) { + dest(i) = array(i).toChar + i += 1 + } + dest + } + + def int32Array2IntArray(array: Int32Array): scala.Array[Int] = + typedArray2arrayImpl(array, new scala.Array(array.length)) + + def float32Array2FloatArray(array: Float32Array): scala.Array[Float] = + typedArray2arrayImpl(array, new scala.Array(array.length)) + + def float64Array2DoubleArray(array: Float64Array): scala.Array[Double] = + typedArray2arrayImpl(array, new scala.Array(array.length)) + + @inline private def typedArray2arrayImpl[ + @specialized(Byte, Short, Int, Float, Double) T, + Repr <: TypedArray[T, Repr]]( + array: Repr, dest: scala.Array[T]): scala.Array[T] = { + val len = dest.length + var i = 0 + while (i < len) { + dest(i) = array(i) + i += 1 + } + dest + } + +} |