/**
* 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.*;
import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError;
import static com.github.anba.es6draft.runtime.internal.Properties.createProperties;
import static com.github.anba.es6draft.runtime.objects.binary.TypedArrayConstructor.TypedArrayCreate;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.Initializable;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.internal.Properties.Accessor;
import com.github.anba.es6draft.runtime.internal.Properties.Attributes;
import com.github.anba.es6draft.runtime.internal.Properties.Function;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.Properties.Value;
import com.github.anba.es6draft.runtime.internal.ScriptIterator;
import com.github.anba.es6draft.runtime.types.BuiltinSymbol;
import com.github.anba.es6draft.runtime.types.Callable;
import com.github.anba.es6draft.runtime.types.Constructor;
import com.github.anba.es6draft.runtime.types.Intrinsics;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.Type;
import com.github.anba.es6draft.runtime.types.builtins.BuiltinConstructor;
/**
* <h1>22 Indexed Collections</h1><br>
* <h2>22.2 TypedArray Objects</h2>
* <ul>
* <li>22.2.1 The %TypedArray% Intrinsic Object
* <li>22.2.2 Properties of the %TypedArray% Intrinsic Object
* </ul>
*/
public final class TypedArrayConstructorPrototype extends BuiltinConstructor implements Initializable {
/**
* Constructs a new TypedArray constructor function.
*
* @param realm
* the realm object
*/
public TypedArrayConstructorPrototype(Realm realm) {
super(realm, "TypedArray", 0);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
}
@Override
public TypedArrayConstructorPrototype clone() {
return new TypedArrayConstructorPrototype(getRealm());
}
/**
* 22.2.1.1 %TypedArray% ( )
*/
@Override
public Object call(ExecutionContext callerContext, Object thisValue, Object... args) {
throw newTypeError(calleeContext(), Messages.Key.InvalidCall, "TypedArray");
}
/**
* 22.2.1.1 %TypedArray% ( )
*/
@Override
public ScriptObject construct(ExecutionContext callerContext, Constructor newTarget, Object... args) {
ExecutionContext calleeContext = calleeContext();
/* step 1 (not applicable) */
/* step 2 (omitted) */
/* step 3 */
if (newTarget == this) {
throw newTypeError(calleeContext, Messages.Key.TypedArrayCreate);
}
/* step 4 */
ScriptObject super_ = getPrototypeOf(calleeContext);
/* step 5 */
if (!IsConstructor(super_)) {
throw newTypeError(calleeContext, Messages.Key.NotConstructor);
}
/* steps 6-7 */
return ((Constructor) super_).construct(calleeContext, newTarget, args);
}
/**
* 22.2.2 Properties of the %TypedArray% Intrinsic Object
*/
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.FunctionPrototype;
@Value(name = "length", attributes = @Attributes(writable = false, enumerable = false, configurable = true))
public static final int length = 0;
@Value(name = "name", attributes = @Attributes(writable = false, enumerable = false, configurable = true))
public static final String name = "TypedArray";
/**
* 22.2.2.3 %TypedArray%.prototype
*/
@Value(name = "prototype",
attributes = @Attributes(writable = false, enumerable = false, configurable = false))
public static final Intrinsics prototype = Intrinsics.TypedArrayPrototype;
/**
* 22.2.2.1 %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param source
* the source object
* @param mapfn
* the optional mapper function
* @param thisArg
* the optional this-argument for the mapper
* @return the new typed array object
*/
@Function(name = "from", arity = 1)
public static Object from(ExecutionContext cx, Object thisValue, Object source, Object mapfn, Object thisArg) {
/* step 1 */
Object c = thisValue;
/* step 2 */
if (!IsConstructor(c)) {
throw newTypeError(cx, Messages.Key.NotConstructor);
}
/* steps 3-4 */
Callable mapper;
boolean mapping;
if (!Type.isUndefined(mapfn)) {
if (!IsCallable(mapfn)) {
throw newTypeError(cx, Messages.Key.NotCallable);
}
mapper = (Callable) mapfn;
mapping = true;
} else {
mapper = null;
mapping = false;
}
/* step 5 (omitted) */
/* step 6 */
List<Object> arrayLike = IterableToArrayLike(cx, source);
/* step 7 */
int len = arrayLike.size();
/* step 8 */
TypedArrayObject targetObj = TypedArrayCreate(cx, (Constructor) c, len);
/* steps 9-10 */
for (int k = 0; k < len; ++k) {
/* step 10.a */
int pk = k;
/* step 10.b */
Object kValue = arrayLike.get(pk);
/* steps 10.c-d */
Object mappedValue;
if (mapping) {
mappedValue = mapper.call(cx, thisArg, kValue, k);
} else {
mappedValue = kValue;
}
/* step 10.e */
targetObj.elementSetDirect(cx, pk, ToNumber(cx, mappedValue));
}
/* step 11 */
return targetObj;
}
/**
* 22.2.2.2 %TypedArray%.of ( ...items )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param items
* the element values
* @return the new typed array object
*/
@Function(name = "of", arity = 0)
public static Object of(ExecutionContext cx, Object thisValue, Object... items) {
/* steps 1-2 */
int len = items.length;
/* step 3 */
Object c = thisValue;
/* step 4 */
if (!IsConstructor(c)) {
throw newTypeError(cx, Messages.Key.NotConstructor);
}
/* step 5 */
TypedArrayObject newObj = TypedArrayCreate(cx, (Constructor) c, len);
/* steps 6-7 */
for (int k = 0; k < len; ++k) {
/* step 7.a */
Object value = items[k];
/* step 7.b */
int pk = k;
/* step 7.c */
newObj.elementSetDirect(cx, pk, ToNumber(cx, value));
}
/* step 8 */
return newObj;
}
/**
* 22.2.2.4 get %TypedArray% [ @@species ]
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @return the species object
*/
@Accessor(name = "get [Symbol.species]", symbol = BuiltinSymbol.species, type = Accessor.Type.Getter)
public static Object species(ExecutionContext cx, Object thisValue) {
/* step 1 */
return thisValue;
}
}
/**
* 22.2.2.1.1 Runtime Semantics: IterableToArrayLike( items )
*
* @param cx
* the execution context
* @param items
* the items object
* @return the items list
*/
public static List<Object> IterableToArrayLike(ExecutionContext cx, Object items) {
/* step 1 */
Callable usingIterator = GetMethod(cx, items, BuiltinSymbol.iterator.get());
/* step 2 */
if (usingIterator != null) {
/* step 2.a */
ScriptIterator<?> iterator = GetScriptIterator(cx, items, usingIterator);
/* step 2.b */
ArrayList<Object> values = new ArrayList<>();
/* steps 2.c-d */
while (iterator.hasNext()) {
Object nextValue = iterator.next();
values.add(nextValue);
}
/* step 2.e */
return values;
}
/* step 3 (note) */
/* step 4 */
return new ScriptArrayList(cx, ToObject(cx, items));
}
private final static class ScriptArrayList extends AbstractList<Object> {
private final ExecutionContext cx;
private final ScriptObject arrayLike;
private final long length;
ScriptArrayList(ExecutionContext cx, ScriptObject arrayLike) {
this.cx = cx;
this.arrayLike = arrayLike;
this.length = ToLength(cx, Get(cx, arrayLike, "length"));
}
@Override
public int size() {
return (int) Math.min(length, Integer.MAX_VALUE);
}
@Override
public Object get(int index) {
if (index < 0 || index >= length) {
throw new IndexOutOfBoundsException();
}
return Get(cx, arrayLike, index);
}
}
}