407 lines
12 KiB
JavaScript
407 lines
12 KiB
JavaScript
/*
|
|
* Copyright (C) 2015-2016 Apple Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// Note that the intrisic @typedArrayLength checks that the argument passed is a typed array
|
|
// and throws if it is not.
|
|
|
|
|
|
// Typed Arrays have their own species constructor function since they need
|
|
// to look up their default constructor, which is expensive. If we used the
|
|
// normal speciesConstructor helper we would need to look up the default
|
|
// constructor every time.
|
|
@globalPrivate
|
|
function typedArraySpeciesConstructor(value)
|
|
{
|
|
"use strict";
|
|
var constructor = value.constructor;
|
|
if (constructor === @undefined)
|
|
return @typedArrayGetOriginalConstructor(value);
|
|
|
|
if (!@isObject(constructor))
|
|
@throwTypeError("|this|.constructor is not an Object or undefined");
|
|
|
|
constructor = constructor.@@species;
|
|
if (@isUndefinedOrNull(constructor))
|
|
return @typedArrayGetOriginalConstructor(value);
|
|
// The lack of an @isConstructor(constructor) check here is not observable because
|
|
// the first thing we will do with the value is attempt to construct the result with it.
|
|
// If any user of this function does not immediately construct the result they need to
|
|
// verify that the result is a constructor.
|
|
return constructor;
|
|
}
|
|
|
|
function every(callback /*, thisArg */)
|
|
{
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.every callback must be a function");
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
if (!callback.@call(thisArg, this[i], i, this))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function find(callback /* [, thisArg] */)
|
|
{
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.find callback must be a function");
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
var elem = this[i];
|
|
if (callback.@call(thisArg, elem, i, this))
|
|
return elem;
|
|
}
|
|
return @undefined;
|
|
}
|
|
|
|
function findLast(callback /* [, thisArg] */)
|
|
{
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.findLast callback must be a function");
|
|
|
|
for (var i = length - 1; i >= 0; i--) {
|
|
var element = this[i];
|
|
if (callback.@call(thisArg, element, i, this))
|
|
return element;
|
|
}
|
|
return @undefined;
|
|
}
|
|
|
|
function findIndex(callback /* [, thisArg] */)
|
|
{
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.findIndex callback must be a function");
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
if (callback.@call(thisArg, this[i], i, this))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
function findLastIndex(callback /* [, thisArg] */)
|
|
{
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.findLastIndex callback must be a function");
|
|
|
|
for (var i = length - 1; i >= 0; i--) {
|
|
if (callback.@call(thisArg, this[i], i, this))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
function forEach(callback /* [, thisArg] */)
|
|
{
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.forEach callback must be a function");
|
|
|
|
for (var i = 0; i < length; i++)
|
|
callback.@call(thisArg, this[i], i, this);
|
|
}
|
|
|
|
function some(callback /* [, thisArg] */)
|
|
{
|
|
// 22.2.3.24
|
|
"use strict";
|
|
var length = @typedArrayLength(this);
|
|
var thisArg = @argument(1);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.some callback must be a function");
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
if (callback.@call(thisArg, this[i], i, this))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@globalPrivate
|
|
function typedArrayElementCompare(array, a, b, comparator)
|
|
{
|
|
"use strict";
|
|
|
|
var result = @toNumber(comparator(a, b));
|
|
|
|
if (@isDetached(array))
|
|
@throwTypeError("Underlying ArrayBuffer has been detached from the view");
|
|
|
|
return result;
|
|
}
|
|
|
|
@globalPrivate
|
|
function typedArrayMerge(array, dst, src, srcIndex, srcEnd, width, comparator)
|
|
{
|
|
"use strict";
|
|
|
|
var left = srcIndex;
|
|
var leftEnd = @min(left + width, srcEnd);
|
|
var right = leftEnd;
|
|
var rightEnd = @min(right + width, srcEnd);
|
|
|
|
for (var dstIndex = left; dstIndex < rightEnd; ++dstIndex) {
|
|
if (right < rightEnd) {
|
|
if (left >= leftEnd || @typedArrayElementCompare(array, src[right], src[left], comparator) < 0) {
|
|
dst[dstIndex] = src[right++];
|
|
continue;
|
|
}
|
|
}
|
|
|
|
dst[dstIndex] = src[left++];
|
|
}
|
|
}
|
|
|
|
@globalPrivate
|
|
function typedArrayMergeSort(array, valueCount, comparator)
|
|
{
|
|
"use strict";
|
|
|
|
var constructor = @typedArrayGetOriginalConstructor(array);
|
|
var buffer = new constructor(valueCount);
|
|
var dst = buffer;
|
|
var src = array;
|
|
|
|
for (var width = 1; width < valueCount; width *= 2) {
|
|
for (var srcIndex = 0; srcIndex < valueCount; srcIndex += 2 * width)
|
|
@typedArrayMerge(array, dst, src, srcIndex, valueCount, width, comparator);
|
|
|
|
var tmp = src;
|
|
src = dst;
|
|
dst = tmp;
|
|
}
|
|
|
|
if (src != array) {
|
|
for (var i = 0; i < valueCount; ++i)
|
|
array[i] = src[i];
|
|
}
|
|
}
|
|
|
|
function sort(comparator)
|
|
{
|
|
"use strict";
|
|
|
|
if (comparator !== @undefined && !@isCallable(comparator))
|
|
@throwTypeError("TypedArray.prototype.sort requires the comparator argument to be a function or undefined");
|
|
|
|
var length = @typedArrayLength(this);
|
|
if (length < 2)
|
|
return;
|
|
|
|
// typedArraySort is not safe when the other thread is modifying content. So if |this| is SharedArrayBuffer,
|
|
// use JS-implemented sorting.
|
|
if (comparator !== @undefined || @isSharedTypedArrayView(this)) {
|
|
if (comparator === @undefined)
|
|
comparator = @typedArrayDefaultComparator;
|
|
@typedArrayMergeSort(this, length, comparator);
|
|
} else
|
|
@typedArraySort(this);
|
|
|
|
return this;
|
|
}
|
|
|
|
function subarray(begin, end)
|
|
{
|
|
"use strict";
|
|
|
|
if (!@isTypedArrayView(this))
|
|
@throwTypeError("|this| should be a typed array view");
|
|
|
|
var start = @toIntegerOrInfinity(begin);
|
|
var finish;
|
|
if (end !== @undefined)
|
|
finish = @toIntegerOrInfinity(end);
|
|
|
|
var constructor = @typedArraySpeciesConstructor(this);
|
|
|
|
return @typedArraySubarrayCreate.@call(this, start, finish, constructor);
|
|
}
|
|
|
|
function reduce(callback /* [, initialValue] */)
|
|
{
|
|
// 22.2.3.19
|
|
"use strict";
|
|
|
|
var length = @typedArrayLength(this);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.reduce callback must be a function");
|
|
|
|
var argumentCount = @argumentCount();
|
|
if (length === 0 && argumentCount < 2)
|
|
@throwTypeError("TypedArray.prototype.reduce of empty array with no initial value");
|
|
|
|
var accumulator, k = 0;
|
|
if (argumentCount > 1)
|
|
accumulator = @argument(1);
|
|
else
|
|
accumulator = this[k++];
|
|
|
|
for (; k < length; k++)
|
|
accumulator = callback.@call(@undefined, accumulator, this[k], k, this);
|
|
|
|
return accumulator;
|
|
}
|
|
|
|
function reduceRight(callback /* [, initialValue] */)
|
|
{
|
|
// 22.2.3.20
|
|
"use strict";
|
|
|
|
var length = @typedArrayLength(this);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.reduceRight callback must be a function");
|
|
|
|
var argumentCount = @argumentCount();
|
|
if (length === 0 && argumentCount < 2)
|
|
@throwTypeError("TypedArray.prototype.reduceRight of empty array with no initial value");
|
|
|
|
var accumulator, k = length - 1;
|
|
if (argumentCount > 1)
|
|
accumulator = @argument(1);
|
|
else
|
|
accumulator = this[k--];
|
|
|
|
for (; k >= 0; k--)
|
|
accumulator = callback.@call(@undefined, accumulator, this[k], k, this);
|
|
|
|
return accumulator;
|
|
}
|
|
|
|
function map(callback /*, thisArg */)
|
|
{
|
|
// 22.2.3.18
|
|
"use strict";
|
|
|
|
var length = @typedArrayLength(this);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.map callback must be a function");
|
|
|
|
var thisArg = @argument(1);
|
|
|
|
var constructor = @typedArraySpeciesConstructor(this);
|
|
var result = new constructor(length);
|
|
if (@typedArrayLength(result) < length)
|
|
@throwTypeError("TypedArray.prototype.map constructed typed array of insufficient length");
|
|
if (@typedArrayContentType(this) !== @typedArrayContentType(result))
|
|
@throwTypeError("TypedArray.prototype.map constructed typed array of different content type from |this|");
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
var mappedValue = callback.@call(thisArg, this[i], i, this);
|
|
result[i] = mappedValue;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function filter(callback /*, thisArg */)
|
|
{
|
|
"use strict";
|
|
|
|
var length = @typedArrayLength(this);
|
|
|
|
if (!@isCallable(callback))
|
|
@throwTypeError("TypedArray.prototype.filter callback must be a function");
|
|
|
|
var thisArg = @argument(1);
|
|
var kept = [];
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
var value = this[i];
|
|
if (callback.@call(thisArg, value, i, this))
|
|
@arrayPush(kept, value);
|
|
}
|
|
var length = kept.length;
|
|
|
|
var constructor = @typedArraySpeciesConstructor(this);
|
|
var result = new constructor(length);
|
|
if (@typedArrayLength(result) < length)
|
|
@throwTypeError("TypedArray.prototype.filter constructed typed array of insufficient length");
|
|
if (@typedArrayContentType(this) !== @typedArrayContentType(result))
|
|
@throwTypeError("TypedArray.prototype.filter constructed typed array of different content type from |this|");
|
|
|
|
for (var i = 0; i < length; i++)
|
|
result[i] = kept[i];
|
|
|
|
return result;
|
|
}
|
|
|
|
function toLocaleString(/* locale, options */)
|
|
{
|
|
"use strict";
|
|
|
|
var length = @typedArrayLength(this);
|
|
|
|
if (length == 0)
|
|
return "";
|
|
|
|
var string = @toString(this[0].toLocaleString(@argument(0), @argument(1)));
|
|
for (var i = 1; i < length; i++)
|
|
string += "," + @toString(this[i].toLocaleString(@argument(0), @argument(1)));
|
|
|
|
return string;
|
|
}
|
|
|
|
function at(index)
|
|
{
|
|
"use strict";
|
|
|
|
var length = @typedArrayLength(this);
|
|
|
|
var k = @toIntegerOrInfinity(index);
|
|
if (k < 0)
|
|
k += length;
|
|
|
|
return (k >= 0 && k < length) ? this[k] : @undefined;
|
|
}
|