/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.objects.binary;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToNumber;
import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError;
import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.GetValueFromBuffer;
import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.IsDetachedBuffer;
import static com.github.anba.es6draft.runtime.objects.binary.ArrayBufferConstructor.SetValueInBuffer;
import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.builtins.IntegerIndexedObject;
/**
* <h1>22 Indexed Collections</h1><br>
* <h2>22.2 TypedArray Objects</h2>
* <ul>
* <li>22.2.7 Properties of TypedArray instances
* </ul>
*/
public final class TypedArrayObject extends IntegerIndexedObject implements ArrayBufferView {
/** [[ViewedArrayBuffer]] */
private final ArrayBuffer buffer;
/** [[ElementType]] */
private final ElementType elementType;
private final int elementShift;
/** [[ByteLength]] */
private final long byteLength;
/** [[ByteOffset]] */
private final long byteOffset;
/** [[ArrayLength]] */
private final long arrayLength;
/**
* Constructs a new TypedArray object.
*
* @param realm
* the realm object
* @param elementType
* the element type
* @param buffer
* the array buffer
* @param byteLength
* the byte length
* @param byteOffset
* the byte offset
* @param arrayLength
* the array length
* @param prototype
* the prototype object
*/
public TypedArrayObject(Realm realm, ElementType elementType, ArrayBuffer buffer, long byteLength, long byteOffset,
long arrayLength, ScriptObject prototype) {
super(realm);
assert elementType != null && buffer != null : "cannot initialize TypedArrayObject with null";
assert byteLength >= 0 : "negative byte length: " + byteLength;
assert byteOffset >= 0 : "negative byte offset: " + byteOffset;
assert arrayLength >= 0 : "negative array length: " + arrayLength;
assert buffer.isDetached() || (byteOffset + byteLength <= buffer.getByteLength());
assert arrayLength * elementType.size() == byteLength : "invalid length: " + byteLength;
this.elementType = elementType;
this.elementShift = 31 - Integer.numberOfLeadingZeros(elementType.size());
this.buffer = buffer;
this.byteLength = byteLength;
this.byteOffset = byteOffset;
this.arrayLength = arrayLength;
setPrototype(prototype);
}
@Override
public long getLength() {
return getArrayLength();
}
@Override
protected boolean elementHas(ExecutionContext cx, long index) {
assert index >= 0;
// 9.4.5.2 [[HasProperty]](P)
/* step 3.c.i */
ArrayBuffer buffer = getBuffer();
/* step 3.c.ii */
if (IsDetachedBuffer(buffer)) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* steps 3.c.iii-vii */
return index < getArrayLength();
}
@Override
protected Object elementGet(ExecutionContext cx, long index) {
assert index >= 0;
/* steps 1-2 (not applicable) */
/* step 3 */
ArrayBuffer buffer = getBuffer();
/* step 4 */
if (IsDetachedBuffer(buffer)) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* steps 5-8 */
if (index >= getArrayLength()) {
return UNDEFINED;
}
/* step 9 */
long offset = getByteOffset();
/* steps 10, 13 */
ElementType elementType = getElementType();
/* steps 11-12 */
long indexedPosition = (index << elementShift) + offset;
/* step 14 */
return GetValueFromBuffer(buffer, indexedPosition, elementType);
}
double elementGetDirect(ExecutionContext cx, long index) {
assert 0 <= index && index < getArrayLength();
/* steps 1-2 (not applicable) */
/* step 3 */
ArrayBuffer buffer = getBuffer();
/* step 4 */
if (IsDetachedBuffer(buffer)) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* steps 5-8 (not applicable) */
/* step 9 */
long offset = getByteOffset();
/* steps 10, 13 */
ElementType elementType = getElementType();
/* steps 11-12 */
long indexedPosition = (index << elementShift) + offset;
/* step 14 */
return GetValueFromBuffer(buffer, indexedPosition, elementType);
}
@Override
protected boolean elementSet(ExecutionContext cx, long index, Object value) {
assert index >= 0;
/* steps 1-2 (not applicable) */
/* steps 3-4 */
double numValue = ToNumber(cx, value);
/* step 5 */
ArrayBuffer buffer = getBuffer();
/* step 6 */
if (IsDetachedBuffer(buffer)) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* steps 7-10 */
if (index >= getArrayLength()) {
return false;
}
/* step 11 */
long offset = getByteOffset();
/* steps 12, 15 */
ElementType elementType = getElementType();
/* steps 13-14 */
long indexedPosition = (index << elementShift) + offset;
/* step 16 */
SetValueInBuffer(buffer, indexedPosition, elementType, numValue);
/* step 17 */
return true;
}
void elementSetDirect(ExecutionContext cx, long index, double numValue) {
assert 0 <= index && index < getArrayLength();
/* steps 1-4 (not applicable) */
/* step 5 */
ArrayBuffer buffer = getBuffer();
/* step 6 */
if (IsDetachedBuffer(buffer)) {
throw newTypeError(cx, Messages.Key.BufferDetached);
}
/* steps 7-10 (not applicable) */
/* step 11 */
long offset = getByteOffset();
/* steps 12, 15 */
ElementType elementType = getElementType();
/* steps 13-14 */
long indexedPosition = (index << elementShift) + offset;
/* steps 16-17 */
SetValueInBuffer(buffer, indexedPosition, elementType, numValue);
/* step 18 (return) */
}
/**
* [[ViewedArrayBuffer]]
*/
@Override
public ArrayBuffer getBuffer() {
return buffer;
}
/**
* [[ElementType]]
*
* @return the element type
*/
public ElementType getElementType() {
return elementType;
}
/**
* [[TypedArrayName]]
*
* @return the typed array name
*/
public String getTypedArrayName() {
return elementType.getConstructorName();
}
/**
* [[ByteLength]]
*/
@Override
public long getByteLength() {
return byteLength;
}
/**
* [[ByteOffset]]
*/
@Override
public long getByteOffset() {
return byteOffset;
}
/**
* [[ArrayLength]]
*
* @return the array length
*/
public long getArrayLength() {
return arrayLength;
}
}