var $arrayUnshift;
var $innerArrayForEach;
var $innerArrayEvery;
+var $innerArrayFilter;
+var $innerArrayMap;
+var $innerArrayReduce;
+var $innerArrayReduceRight;
+var $innerArraySome;
(function(global, shared, exports) {
// The following functions cannot be made efficient on sparse arrays while
// preserving the semantics, since the calls to the receiver function can add
// or delete elements from the array.
-function ArrayFilter(f, receiver) {
- CHECK_OBJECT_COERCIBLE(this, "Array.prototype.filter");
-
- // Pull out the length so that modifications to the length in the
- // loop will not affect the looping and side effects are visible.
- var array = $toObject(this);
- var length = $toUint32(array.length);
-
+function InnerArrayFilter(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
return result;
}
+function ArrayFilter(f, receiver) {
+ CHECK_OBJECT_COERCIBLE(this, "Array.prototype.filter");
+
+ // Pull out the length so that modifications to the length in the
+ // loop will not affect the looping and side effects are visible.
+ var array = $toObject(this);
+ var length = $toUint32(array.length);
+
+ return InnerArrayFilter(f, receiver, array, length);
+}
+
function InnerArrayForEach(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
}
-// Executes the function once for each element present in the
-// array until it finds one where callback returns true.
-function ArraySome(f, receiver) {
- CHECK_OBJECT_COERCIBLE(this, "Array.prototype.some");
-
- // Pull out the length so that modifications to the length in the
- // loop will not affect the looping and side effects are visible.
- var array = $toObject(this);
- var length = TO_UINT32(array.length);
-
+function InnerArraySome(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
}
+// Executes the function once for each element present in the
+// array until it finds one where callback returns true.
+function ArraySome(f, receiver) {
+ CHECK_OBJECT_COERCIBLE(this, "Array.prototype.some");
+
+ // Pull out the length so that modifications to the length in the
+ // loop will not affect the looping and side effects are visible.
+ var array = $toObject(this);
+ var length = TO_UINT32(array.length);
+ return InnerArraySome(f, receiver, array, length);
+}
+
+
function InnerArrayEvery(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
}
-function ArrayMap(f, receiver) {
- CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
-
- // Pull out the length so that modifications to the length in the
- // loop will not affect the looping and side effects are visible.
- var array = $toObject(this);
- var length = TO_UINT32(array.length);
-
+function InnerArrayMap(f, receiver, array, length) {
if (!IS_SPEC_FUNCTION(f)) throw MakeTypeError(kCalledNonCallable, f);
var needs_wrapper = false;
if (IS_NULL(receiver)) {
}
+function ArrayMap(f, receiver) {
+ CHECK_OBJECT_COERCIBLE(this, "Array.prototype.map");
+
+ // Pull out the length so that modifications to the length in the
+ // loop will not affect the looping and side effects are visible.
+ var array = $toObject(this);
+ var length = TO_UINT32(array.length);
+ return InnerArrayMap(f, receiver, array, length);
+}
+
+
function ArrayIndexOf(element, index) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.indexOf");
}
-function ArrayReduce(callback, current) {
- CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduce");
-
- // Pull out the length so that modifications to the length in the
- // loop will not affect the looping and side effects are visible.
- var array = $toObject(this);
- var length = $toUint32(array.length);
-
+function InnerArrayReduce(callback, current, array, length, argumentsLength) {
if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError(kCalledNonCallable, callback);
}
var is_array = IS_ARRAY(array);
var i = 0;
- find_initial: if (%_ArgumentsLength() < 2) {
+ find_initial: if (argumentsLength < 2) {
for (; i < length; i++) {
if (HAS_INDEX(array, i, is_array)) {
current = array[i++];
}
-function ArrayReduceRight(callback, current) {
- CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduceRight");
+function ArrayReduce(callback, current) {
+ CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduce");
- // Pull out the length so that side effects are visible before the
- // callback function is checked.
+ // Pull out the length so that modifications to the length in the
+ // loop will not affect the looping and side effects are visible.
var array = $toObject(this);
var length = $toUint32(array.length);
+ return InnerArrayReduce(callback, current, array, length,
+ %_ArgumentsLength());
+}
+
+function InnerArrayReduceRight(callback, current, array, length,
+ argumentsLength) {
if (!IS_SPEC_FUNCTION(callback)) {
throw MakeTypeError(kCalledNonCallable, callback);
}
var is_array = IS_ARRAY(array);
var i = length - 1;
- find_initial: if (%_ArgumentsLength() < 2) {
+ find_initial: if (argumentsLength < 2) {
for (; i >= 0; i--) {
if (HAS_INDEX(array, i, is_array)) {
current = array[i--];
return current;
}
+
+function ArrayReduceRight(callback, current) {
+ CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reduceRight");
+
+ // Pull out the length so that side effects are visible before the
+ // callback function is checked.
+ var array = $toObject(this);
+ var length = $toUint32(array.length);
+ return InnerArrayReduceRight(callback, current, array, length,
+ %_ArgumentsLength());
+}
+
// ES5, 15.4.3.2
function ArrayIsArray(obj) {
return IS_ARRAY(obj);
$arraySplice = ArraySplice;
$arrayUnshift = ArrayUnshift;
-$innerArrayForEach = InnerArrayForEach;
$innerArrayEvery = InnerArrayEvery;
+$innerArrayFilter = InnerArrayFilter;
+$innerArrayForEach = InnerArrayForEach;
+$innerArrayMap = InnerArrayMap;
+$innerArrayReduce = InnerArrayReduce;
+$innerArrayReduceRight = InnerArrayReduceRight;
+$innerArraySome = InnerArraySome;
});
// -------------------------------------------------------------------
+function ConstructTypedArray(constructor, array) {
+ // TODO(littledan): This is an approximation of the spec, which requires
+ // that only real TypedArray classes should be accepted (22.2.2.1.1)
+ if (!IS_SPEC_OBJECT(constructor) || IS_UNDEFINED(constructor.prototype) ||
+ !%HasOwnProperty(constructor.prototype, "BYTES_PER_ELEMENT")) {
+ throw MakeTypeError(kNotTypedArray);
+ }
+
+ // TODO(littledan): The spec requires that, rather than directly calling
+ // the constructor, a TypedArray is created with the proper proto and
+ // underlying size and element size, and elements are put in one by one.
+ // By contrast, this would allow subclasses to make a radically different
+ // constructor with different semantics.
+ return new constructor(array);
+}
+
+function ConstructTypedArrayLike(typedArray, arrayContents) {
+ // TODO(littledan): The spec requires that we actuallly use
+ // typedArray.constructor[Symbol.species] (bug v8:4093)
+ return new typedArray.constructor(arrayContents);
+}
+
function TypedArrayCopyWithin(target, start, end) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
%FunctionSetLength(TypedArrayForEach, 1);
// ES6 draft 04-05-14 section 22.2.3.8
-function TypedArrayFill(value, start , end) {
+function TypedArrayFill(value, start, end) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
}
%FunctionSetLength(TypedArrayFill, 1);
+// ES6 draft 07-15-13, section 22.2.3.9
+function TypedArrayFilter(predicate, thisArg) {
+ if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+ var length = %_TypedArrayGetLength(this);
+ var array = $innerArrayFilter(predicate, thisArg, this, length);
+ return ConstructTypedArrayLike(this, array);
+}
+%FunctionSetLength(TypedArrayFilter, 1);
+
// ES6 draft 07-15-13, section 22.2.3.10
function TypedArrayFind(predicate, thisArg) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
%FunctionSetLength(TypedArrayFindIndex, 1);
+// ES6 draft 07-15-13, section 22.2.3.18
+function TypedArrayMap(predicate, thisArg) {
+ if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+ // TODO(littledan): Preallocate rather than making an intermediate
+ // array, for better performance.
+ var length = %_TypedArrayGetLength(this);
+ var array = $innerArrayMap(predicate, thisArg, this, length);
+ return ConstructTypedArrayLike(this, array);
+}
+%FunctionSetLength(TypedArrayMap, 1);
+
+
+// ES6 draft 07-15-13, section 22.2.3.19
+function TypedArrayReduce(callback, current) {
+ if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+ var length = %_TypedArrayGetLength(this);
+ return $innerArrayReduce(callback, current, this, length,
+ %_ArgumentsLength());
+}
+%FunctionSetLength(TypedArrayReduce, 1);
+
+
+// ES6 draft 07-15-13, section 22.2.3.19
+function TypedArrayReduceRight(callback, current) {
+ if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+ var length = %_TypedArrayGetLength(this);
+ return $innerArrayReduceRight(callback, current, this, length,
+ %_ArgumentsLength());
+}
+%FunctionSetLength(TypedArrayReduceRight, 1);
+
+
+// ES6 draft 05-05-15, section 22.2.3.24
+function TypedArraySome(f, receiver) {
+ if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
+
+ var length = %_TypedArrayGetLength(this);
+
+ return $innerArraySome(f, receiver, this, length);
+}
+%FunctionSetLength(TypedArraySome, 1);
+
+
// ES6 draft 08-24-14, section 22.2.2.2
function TypedArrayOf() {
var length = %_ArgumentsLength();
$installFunctions(GlobalNAME.prototype, DONT_ENUM, [
"copyWithin", TypedArrayCopyWithin,
"every", TypedArrayEvery,
- "forEach", TypedArrayForEach,
+ "fill", TypedArrayFill,
+ "filter", TypedArrayFilter,
"find", TypedArrayFind,
"findIndex", TypedArrayFindIndex,
- "fill", TypedArrayFill
+ "forEach", TypedArrayForEach,
+ "map", TypedArrayMap,
+ "reduce", TypedArrayReduce,
+ "reduceRight", TypedArrayReduceRight,
+ "some", TypedArraySome
]);
endmacro
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays
+
+// Tests for standard TypedArray array iteration functions.
+
+var typedArrayConstructors = [
+ Uint8Array,
+ Int8Array,
+ Uint16Array,
+ Int16Array,
+ Uint32Array,
+ Int32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array
+];
+
+function assertArrayLikeEquals(expected, value, type) {
+ assertEquals(value.__proto__, type.prototype);
+ assertEquals(expected.length, value.length);
+ for (var i = 0; i < value.length; ++i) {
+ assertEquals(expected[i], value[i]);
+ }
+}
+
+for (var constructor of typedArrayConstructors) {
+ (function TypedArrayFilterTest() {
+ // Simple use.
+ var a = new constructor([0, 1]);
+ assertArrayLikeEquals([0], a.filter(function(n) { return n == 0; }),
+ constructor);
+ assertArrayLikeEquals([0, 1], a, constructor);
+
+ // Use specified object as this object when calling the function.
+ var o = { value: 42 }
+ a = new constructor([1, 42, 3, 42, 4]);
+ assertArrayLikeEquals([42, 42], a.filter(function(n) {
+ return this.value == n
+ }, o), constructor);
+
+ // Modify original array.
+ a = new constructor([1, 42, 3, 42, 4]);
+ assertArrayLikeEquals([42, 42], a.filter(function(n, index, array) {
+ array[index] = 43; return 42 == n;
+ }), constructor);
+ assertArrayLikeEquals([43, 43, 43, 43, 43], a, constructor);
+
+ // Create a new object in each function call when receiver is a
+ // primitive value. See ECMA-262, Annex C.
+ a = [];
+ new constructor([1, 2]).filter(function() { a.push(this) }, '');
+ assertTrue(a[0] !== a[1]);
+
+ // Do not create a new object otherwise.
+ a = [];
+ new constructor([1, 2]).filter(function() { a.push(this) }, {});
+ assertEquals(a[0], a[1]);
+
+ // In strict mode primitive values should not be coerced to an object.
+ a = [];
+ new constructor([1, 2]).filter(function() {
+ 'use strict';
+ a.push(this);
+ }, '');
+ assertEquals('', a[0]);
+ assertEquals(a[0], a[1]);
+
+ // Calling this method on other types is a TypeError
+ assertThrows(function() {
+ constructor.prototype.filter.call([], function() {});
+ }, TypeError);
+
+ // Shadowing the length property doesn't change anything
+ a = new constructor([1, 2]);
+ Object.defineProperty(a, 'length', { value: 1 });
+ assertArrayLikeEquals([2], a.filter(function(elt) {
+ return elt == 2;
+ }), constructor);
+ })();
+
+ (function TypedArrayMapTest() {
+ var a = new constructor([0, 1, 2, 3, 4]);
+
+ // Simple use.
+ var result = [1, 2, 3, 4, 5];
+ assertArrayLikeEquals(result, a.map(function(n) { return n + 1; }),
+ constructor);
+ assertEquals(a, a);
+
+ // Use specified object as this object when calling the function.
+ var o = { delta: 42 }
+ result = [42, 43, 44, 45, 46];
+ assertArrayLikeEquals(result, a.map(function(n) {
+ return this.delta + n;
+ }, o), constructor);
+
+ // Modify original array.
+ a = new constructor([0, 1, 2, 3, 4]);
+ result = [1, 2, 3, 4, 5];
+ assertArrayLikeEquals(result, a.map(function(n, index, array) {
+ array[index] = n + 1;
+ return n + 1;
+ }), constructor);
+ assertArrayLikeEquals(result, a, constructor);
+
+ // Create a new object in each function call when receiver is a
+ // primitive value. See ECMA-262, Annex C.
+ a = [];
+ new constructor([1, 2]).map(function() { a.push(this) }, '');
+ assertTrue(a[0] !== a[1]);
+
+ // Do not create a new object otherwise.
+ a = [];
+ new constructor([1, 2]).map(function() { a.push(this) }, {});
+ assertEquals(a[0], a[1]);
+
+ // In strict mode primitive values should not be coerced to an object.
+ a = [];
+ new constructor([1, 2]).map(function() { 'use strict'; a.push(this); }, '');
+ assertEquals('', a[0]);
+ assertEquals(a[0], a[1]);
+
+ // Test that the result is converted to the right type
+ assertArrayLikeEquals([3, 3], new constructor([1, 2]).map(function() {
+ return "3";
+ }), constructor);
+ if (constructor !== Float32Array && constructor !== Float64Array) {
+ assertArrayLikeEquals([0, 0], new constructor([1, 2]).map(function() {
+ return NaN;
+ }), constructor);
+ }
+ })();
+
+ //
+ // %TypedArray%.prototype.some
+ //
+ (function TypedArraySomeTest() {
+ var a = new constructor([0, 1, 2, 3, 4]);
+
+ // Simple use.
+ assertTrue(a.some(function(n) { return n == 3}));
+ assertFalse(a.some(function(n) { return n == 5}));
+
+ // Use specified object as this object when calling the function.
+ var o = { element: 42 };
+ a = new constructor([1, 42, 3]);
+ assertTrue(a.some(function(n) { return this.element == n; }, o));
+ a = new constructor([1]);
+ assertFalse(a.some(function(n) { return this.element == n; }, o));
+
+ // Modify original array.
+ a = new constructor([0, 1, 2, 3]);
+ assertTrue(a.some(function(n, index, array) {
+ array[index] = n + 1;
+ return n == 2;
+ }));
+ assertArrayLikeEquals([1, 2, 3, 3], a, constructor);
+
+ // Create a new object in each function call when receiver is a
+ // primitive value. See ECMA-262, Annex C.
+ a = [];
+ new constructor([1, 2]).some(function() { a.push(this) }, '');
+ assertTrue(a[0] !== a[1]);
+
+ // Do not create a new object otherwise.
+ a = [];
+ new constructor([1, 2]).some(function() { a.push(this) }, {});
+ assertEquals(a[0], a[1]);
+
+ // In strict mode primitive values should not be coerced to an object.
+ a = [];
+ new constructor([1, 2]).some(function() {
+ 'use strict';
+ a.push(this);
+ }, '');
+ assertEquals('', a[0]);
+ assertEquals(a[0], a[1]);
+
+ // Calling this method on other types is a TypeError
+ assertThrows(function() {
+ constructor.prototype.some.call([], function() {});
+ }, TypeError);
+
+ // Shadowing the length property doesn't change anything
+ a = new constructor([1, 2]);
+ Object.defineProperty(a, 'length', { value: 1 });
+ assertEquals(true, a.some(function(elt) { return elt == 2; }));
+ assertEquals(false, Array.prototype.some.call(a, function(elt) {
+ return elt == 2;
+ }));
+ })();
+
+}
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --harmony-arrays --allow-natives-syntax
+
+var typedArrayConstructors = [
+ Uint8Array,
+ Int8Array,
+ Uint16Array,
+ Int16Array,
+ Uint32Array,
+ Int32Array,
+ Uint8ClampedArray,
+ Float32Array,
+ Float64Array
+];
+
+function clone(v) {
+ // Shallow-copies arrays, returns everything else verbatim.
+ if (v instanceof Array) {
+ // Shallow-copy an array.
+ var newArray = new Array(v.length);
+ for (var i in v) {
+ newArray[i] = v[i];
+ }
+ return newArray;
+ }
+ return v;
+}
+
+
+// Creates a callback function for reduce/reduceRight that tests the number
+// of arguments and otherwise behaves as "func", but which also
+// records all calls in an array on the function (as arrays of arguments
+// followed by result).
+function makeRecorder(func, testName) {
+ var record = [];
+ var f = function recorder(a, b, i, s) {
+ assertEquals(4, arguments.length,
+ testName + "(number of arguments: " + arguments.length + ")");
+ assertEquals("number", typeof(i), testName + "(index must be number)");
+ assertEquals(s[i], b, testName + "(current argument is at index)");
+ if (record.length > 0) {
+ var prevRecord = record[record.length - 1];
+ var prevResult = prevRecord[prevRecord.length - 1];
+ assertEquals(prevResult, a,
+ testName + "(prev result -> current input)");
+ }
+ var args = [clone(a), clone(b), i, clone(s)];
+ var result = func.apply(this, arguments);
+ args.push(clone(result));
+ record.push(args);
+ return result;
+ };
+ f.record = record;
+ return f;
+}
+
+
+function testReduce(type,
+ testName,
+ expectedResult,
+ expectedCalls,
+ array,
+ combine,
+ init) {
+ var rec = makeRecorder(combine);
+ var result;
+ var performsCall;
+ if (arguments.length > 6) {
+ result = array[type](rec, init);
+ } else {
+ result = array[type](rec);
+ }
+ var calls = rec.record;
+ assertEquals(expectedCalls.length, calls.length,
+ testName + " (number of calls)");
+ for (var i = 0; i < expectedCalls.length; i++) {
+ assertEquals(expectedCalls[i], calls[i],
+ testName + " (call " + (i + 1) + ")");
+ }
+ assertEquals(expectedResult, result, testName + " (result)");
+}
+
+
+function sum(a, b) { return a + b; }
+function prod(a, b) { return a * b; }
+function dec(a, b, i, arr) { return a + b * Math.pow(10, arr.length - i - 1); }
+function accumulate(acc, elem, i) { acc[i] = elem; return acc; }
+
+for (var constructor of typedArrayConstructors) {
+ // ---- Test Reduce[Left]
+
+ var simpleArray = new constructor([2,4,6])
+
+ testReduce("reduce", "SimpleReduceSum", 12,
+ [[0, 2, 0, simpleArray, 2],
+ [2, 4, 1, simpleArray, 6],
+ [6, 6, 2, simpleArray, 12]],
+ simpleArray, sum, 0);
+
+ testReduce("reduce", "SimpleReduceProd", 48,
+ [[1, 2, 0, simpleArray, 2],
+ [2, 4, 1, simpleArray, 8],
+ [8, 6, 2, simpleArray, 48]],
+ simpleArray, prod, 1);
+
+ testReduce("reduce", "SimpleReduceDec", 246,
+ [[0, 2, 0, simpleArray, 200],
+ [200, 4, 1, simpleArray, 240],
+ [240, 6, 2, simpleArray, 246]],
+ simpleArray, dec, 0);
+
+ testReduce("reduce", "SimpleReduceAccumulate", [2, 4, 6],
+ [[[], 2, 0, simpleArray, [2]],
+ [[2], 4, 1, simpleArray, [2, 4]],
+ [[2,4], 6, 2, simpleArray, [2, 4, 6]]],
+ simpleArray, accumulate, []);
+
+
+ testReduce("reduce", "EmptyReduceSum", 0, [], [], sum, 0);
+ testReduce("reduce", "EmptyReduceProd", 1, [], [], prod, 1);
+ testReduce("reduce", "EmptyReduceDec", 0, [], [], dec, 0);
+ testReduce("reduce", "EmptyReduceAccumulate", [], [], [], accumulate, []);
+
+ testReduce("reduce", "EmptyReduceSumNoInit", 0, [], [0], sum);
+ testReduce("reduce", "EmptyReduceProdNoInit", 1, [], [1], prod);
+ testReduce("reduce", "EmptyReduceDecNoInit", 0, [], [0], dec);
+ testReduce("reduce", "EmptyReduceAccumulateNoInit", [], [], [[]], accumulate);
+
+ // ---- Test ReduceRight
+
+ testReduce("reduceRight", "SimpleReduceRightSum", 12,
+ [[0, 6, 2, simpleArray, 6],
+ [6, 4, 1, simpleArray, 10],
+ [10, 2, 0, simpleArray, 12]],
+ simpleArray, sum, 0);
+
+ testReduce("reduceRight", "SimpleReduceRightProd", 48,
+ [[1, 6, 2, simpleArray, 6],
+ [6, 4, 1, simpleArray, 24],
+ [24, 2, 0, simpleArray, 48]],
+ simpleArray, prod, 1);
+
+ testReduce("reduceRight", "SimpleReduceRightDec", 246,
+ [[0, 6, 2, simpleArray, 6],
+ [6, 4, 1, simpleArray, 46],
+ [46, 2, 0, simpleArray, 246]],
+ simpleArray, dec, 0);
+
+
+ testReduce("reduceRight", "EmptyReduceRightSum", 0, [], [], sum, 0);
+ testReduce("reduceRight", "EmptyReduceRightProd", 1, [], [], prod, 1);
+ testReduce("reduceRight", "EmptyReduceRightDec", 0, [], [], dec, 0);
+ testReduce("reduceRight", "EmptyReduceRightAccumulate", [],
+ [], [], accumulate, []);
+
+ testReduce("reduceRight", "EmptyReduceRightSumNoInit", 0, [], [0], sum);
+ testReduce("reduceRight", "EmptyReduceRightProdNoInit", 1, [], [1], prod);
+ testReduce("reduceRight", "EmptyReduceRightDecNoInit", 0, [], [0], dec);
+ testReduce("reduceRight", "EmptyReduceRightAccumulateNoInit",
+ [], [], [[]], accumulate);
+
+ // Ignore non-array properties:
+
+ var arrayPlus = [1,2,3];
+ arrayPlus[-1] = NaN;
+ arrayPlus[Math.pow(2,32)] = NaN;
+ arrayPlus[NaN] = NaN;
+ arrayPlus["00"] = NaN;
+ arrayPlus["02"] = NaN;
+ arrayPlus["-0"] = NaN;
+
+ testReduce("reduce", "ArrayWithNonElementPropertiesReduce", 6,
+ [[0, 1, 0, arrayPlus, 1],
+ [1, 2, 1, arrayPlus, 3],
+ [3, 3, 2, arrayPlus, 6],
+ ], arrayPlus, sum, 0);
+
+ testReduce("reduceRight", "ArrayWithNonElementPropertiesReduceRight", 6,
+ [[0, 3, 2, arrayPlus, 3],
+ [3, 2, 1, arrayPlus, 5],
+ [5, 1, 0, arrayPlus, 6],
+ ], arrayPlus, sum, 0);
+
+
+ // Test error conditions:
+
+ var exception = false;
+ try {
+ new constructor([1]).reduce("not a function");
+ } catch (e) {
+ exception = true;
+ assertTrue(e instanceof TypeError,
+ "reduce callback not a function not throwing TypeError");
+ assertTrue(e.message.indexOf(" is not a function") >= 0,
+ "reduce non function TypeError type");
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ new constructor([1]).reduceRight("not a function");
+ } catch (e) {
+ exception = true;
+ assertTrue(e instanceof TypeError,
+ "reduceRight callback not a function not throwing TypeError");
+ assertTrue(e.message.indexOf(" is not a function") >= 0,
+ "reduceRight non function TypeError type");
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ new constructor([]).reduce(sum);
+ } catch (e) {
+ exception = true;
+ assertTrue(e instanceof TypeError,
+ "reduce no initial value not throwing TypeError");
+ assertEquals("Reduce of empty array with no initial value", e.message,
+ "reduce no initial TypeError type");
+ }
+ assertTrue(exception);
+
+ exception = false;
+ try {
+ new constructor([]).reduceRight(sum);
+ } catch (e) {
+ exception = true;
+ assertTrue(e instanceof TypeError,
+ "reduceRight no initial value not throwing TypeError");
+ assertEquals("Reduce of empty array with no initial value", e.message,
+ "reduceRight no initial TypeError type");
+ }
+ assertTrue(exception);
+
+ // Reduce fails when called on non-TypedArrays
+ assertThrows(function() {
+ constructor.prototype.reduce.call([], function() {}, null);
+ }, TypeError);
+ assertThrows(function() {
+ constructor.prototype.reduceRight.call([], function() {}, null);
+ }, TypeError);
+
+ // Shadowing length doesn't affect every, unlike Array.prototype.every
+ var a = new constructor([1, 2]);
+ Object.defineProperty(a, 'length', {value: 1});
+ assertEquals(a.reduce(sum, 0), 3);
+ assertEquals(Array.prototype.reduce.call(a, sum, 0), 1);
+ assertEquals(a.reduceRight(sum, 0), 3);
+ assertEquals(Array.prototype.reduceRight.call(a, sum, 0), 1);
+
+ assertEquals(1, constructor.prototype.reduce.length);
+ assertEquals(1, constructor.prototype.reduceRight.length);
+}