Commit 95d779ec authored by dehrenberg's avatar dehrenberg Committed by Commit bot

Implement %TypedArray%.prototype.{reduce,reduceRight}

This patch implements the last two methods on TypedArrays. These
were previously committed and led to a test failure.

BUG=v8:3578
LOG=Y
R=adamk

Review URL: https://codereview.chromium.org/1154423014

Cr-Commit-Position: refs/heads/master@{#28773}
parent 51439db3
......@@ -1492,21 +1492,14 @@ function ArrayLastIndexOf(element, index) {
}
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++];
......@@ -1529,21 +1522,27 @@ function ArrayReduce(callback, current) {
}
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--];
......@@ -1565,6 +1564,18 @@ function ArrayReduceRight(callback, current) {
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);
......@@ -1673,6 +1684,8 @@ utils.Export(function(to) {
to.InnerArrayJoin = InnerArrayJoin;
to.InnerArrayLastIndexOf = InnerArrayLastIndexOf;
to.InnerArrayMap = InnerArrayMap;
to.InnerArrayReduce = InnerArrayReduce;
to.InnerArrayReduceRight = InnerArrayReduceRight;
to.InnerArrayReverse = InnerArrayReverse;
to.InnerArraySome = InnerArraySome;
to.InnerArraySort = InnerArraySort;
......
......@@ -64,6 +64,8 @@ utils.Import(function(from) {
InnerArrayJoin = from.InnerArrayJoin;
InnerArrayLastIndexOf = from.InnerArrayLastIndexOf;
InnerArrayMap = from.InnerArrayMap;
InnerArrayReduce = from.InnerArrayReduce;
InnerArrayReduceRight = from.InnerArrayReduceRight;
InnerArrayReverse = from.InnerArrayReverse;
InnerArraySome = from.InnerArraySome;
InnerArraySort = from.InnerArraySort;
......@@ -265,11 +267,13 @@ function TypedArrayToLocaleString() {
return InnerArrayToLocaleString(this, length);
}
// ES6 section 22.2.3.28
function TypedArrayToString() {
return %_CallFunction(this, ArrayToString);
}
// ES6 section 22.2.3.14
function TypedArrayJoin(separator) {
if (!%IsTypedArray(this)) throw MakeTypeError(kNotTypedArray);
......@@ -280,6 +284,28 @@ function TypedArrayJoin(separator) {
}
// 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 08-24-14, section 22.2.2.2
function TypedArrayOf() {
var length = %_ArgumentsLength();
......@@ -320,6 +346,8 @@ macro EXTEND_TYPED_ARRAY(NAME)
"lastIndexOf", TypedArrayLastIndexOf,
"forEach", TypedArrayForEach,
"map", TypedArrayMap,
"reduce", TypedArrayReduce,
"reduceRight", TypedArrayReduceRight,
"reverse", TypedArrayReverse,
"some", TypedArraySome,
"sort", TypedArraySort,
......
......@@ -164,6 +164,8 @@ function PostNatives(utils) {
"InnerArrayJoin",
"InnerArrayLastIndexOf",
"InnerArrayMap",
"InnerArrayReduce",
"InnerArrayReduceRight",
"InnerArrayReverse",
"InnerArraySome",
"InnerArraySort",
......
// 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
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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment