public static EcmaValue From([This] EcmaValue thisValue, EcmaValue source, EcmaValue mapFn, EcmaValue thisArg) { if (!thisValue.IsCallable || !thisValue.ToObject().IsConstructor) { throw new EcmaTypeErrorException(InternalString.Error.NotConstructor); } if (mapFn != default) { Guard.ArgumentIsCallable(mapFn); } if (source.IsNullOrUndefined) { return(thisValue.Construct(0)); } RuntimeObject obj = source.ToObject(); RuntimeObject iterator = obj.GetMethod(WellKnownSymbol.Iterator); TypedArray array; if (iterator != null) { List <EcmaValue> values = new List <EcmaValue>(obj.GetIterator()); array = thisValue.Construct(values.Count).GetUnderlyingObject <TypedArray>(); if (array.Length < values.Count) { throw new EcmaTypeErrorException(InternalString.Error.TypedArrayBufferTooSmall); } int i = 0; foreach (EcmaValue v in values) { EcmaValue value = v; if (mapFn != default) { value = mapFn.Call(thisArg, value, i); } array.Set(i++, value); } } else { long length = source[WellKnownProperty.Length].ToLength(); array = thisValue.Construct(length).GetUnderlyingObject <TypedArray>(); if (array.Length < length) { throw new EcmaTypeErrorException(InternalString.Error.TypedArrayBufferTooSmall); } for (int i = 0; i < length; i++) { EcmaValue value = obj.Get(i); if (mapFn != default) { value = mapFn.Call(thisArg, value, i); } array.Set(i, value); } } return(array); }
public static EcmaValue From([This] EcmaValue thisValue, EcmaValue arrayLike, EcmaValue mapFn, EcmaValue thisArg) { RuntimeObject items = arrayLike.ToObject(); if (mapFn != default) { Guard.ArgumentIsCallable(mapFn); } bool usingIterator = items.GetMethod(WellKnownSymbol.Iterator) != null; long initialLen = usingIterator ? 0 : arrayLike[WellKnownProperty.Length].ToLength(); RuntimeObject arr; if (thisValue.IsCallable && thisValue.ToObject().IsConstructor) { arr = thisValue.Construct(usingIterator ? EcmaValue.EmptyArray : new EcmaValue[] { initialLen }).ToObject(); } else { arr = new EcmaArray(initialLen); } if (usingIterator) { foreach (EcmaValue value in items.GetIterator()) { ArrayPrototype.ThrowIfLengthExceeded(initialLen + 1); EcmaValue value1 = value; if (mapFn != default) { value1 = mapFn.Call(thisArg, value, initialLen); } arr.CreateDataPropertyOrThrow(initialLen++, value1); } } else { for (long i = 0; i < initialLen; i++) { EcmaValue value = items[i]; if (mapFn != default) { value = mapFn.Call(thisArg, value, i); } arr.CreateDataPropertyOrThrow(i, value); } } arr.SetOrThrow(WellKnownProperty.Length, initialLen); return(arr); }
public static EcmaValue ConstructTypedArray(TypedArrayKind kind, EcmaValue thisValue, EcmaValue[] args) { TypedArray array = thisValue.GetUnderlyingObject <TypedArray>(); if (args.Length == 0) { array.Init(0); return(thisValue); } if (args[0].Type != EcmaValueType.Object) { array.Init(args[0].ToIndex()); return(thisValue); } RuntimeObject obj = args[0].ToObject(); long bytesPerElement = array.ElementSize; if (obj is TypedArray srcArray) { Guard.BufferNotDetached(srcArray); RuntimeObject bufferConstructor; if (srcArray.Buffer.IsShared) { bufferConstructor = srcArray.Realm.GetRuntimeObject(WellKnownObject.ArrayBuffer); } else { bufferConstructor = RuntimeObject.GetSpeciesConstructor(srcArray.Buffer, WellKnownObject.ArrayBuffer); } if (srcArray.ArrayKind == kind) { ArrayBuffer buffer = srcArray.Buffer.Clone(srcArray.ByteOffset, bytesPerElement * srcArray.Length, bufferConstructor); array.Init(buffer); } else { ArrayBuffer buffer = ArrayBuffer.AllocateArrayBuffer(bufferConstructor, bytesPerElement * srcArray.Length); Guard.BufferNotDetached(srcArray); array.Init(buffer); for (int i = 0, j = 0, count = srcArray.Length; i < count; i++, j++) { array.SetValueInBuffer(j, srcArray.GetValueFromBuffer(i)); } } return(thisValue); } if (obj is ArrayBuffer srcBuffer) { long offset = args.Length > 1 ? args[1].ToIndex() : 0; if ((offset % bytesPerElement) != 0) { throw new EcmaRangeErrorException(InternalString.Error.TypedArrayInvalidOffset, TypedArrayInfo.GetTypedArrayName(array.ArrayKind), bytesPerElement); } long length; if (args.Length <= 2 || args[2] == default) { Guard.BufferNotDetached(srcBuffer); if ((srcBuffer.ByteLength % bytesPerElement) != 0) { throw new EcmaRangeErrorException(InternalString.Error.TypedArrayInvalidByteLength, TypedArrayInfo.GetTypedArrayName(array.ArrayKind), bytesPerElement); } if (srcBuffer.ByteLength < offset) { throw new EcmaRangeErrorException(InternalString.Error.BufferOffsetOutOfBound, offset); } length = srcBuffer.ByteLength - offset; } else { length = args[2].ToIndex() * bytesPerElement; Guard.BufferNotDetached(srcBuffer); if (offset + length > srcBuffer.ByteLength) { throw new EcmaRangeErrorException(InternalString.Error.TypedArrayInvalidLength, length); } } array.Init(srcBuffer, offset, length); return(thisValue); } RuntimeObject iterator = obj.GetMethod(WellKnownSymbol.Iterator); if (iterator != null) { List <EcmaValue> values = new List <EcmaValue>(obj.GetIterator()); array.Init(values.Count); int i = 0; foreach (EcmaValue v in values) { array.Set(i++, v); } } else { long length = obj[WellKnownProperty.Length].ToLength(); array.Init((int)length); for (int i = 0; i < length; i++) { array.Set(i, obj[i]); } } return(thisValue); }