Commit c561933a authored by oliver@apple.com's avatar oliver@apple.com

Bug 25229: Need support for Array.prototype.reduceRight

<https://bugs.webkit.org/show_bug.cgi?id=25229>

Reviewed by Gavin Barraclough.

Implement Array.reduceRight


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@42570 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent c193bdac
2009-04-15 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
Bug 25229: Need support for Array.prototype.reduceRight
<https://bugs.webkit.org/show_bug.cgi?id=25229>
Implement Array.reduceRight
* runtime/ArrayPrototype.cpp:
(JSC::arrayProtoFuncReduceRight):
2009-04-15 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
......@@ -58,6 +58,7 @@ static JSValuePtr arrayProtoFuncIndexOf(ExecState*, JSObject*, JSValuePtr, const
static JSValuePtr arrayProtoFuncFilter(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncMap(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncReduce(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncReduceRight(ExecState*, JSObject*, JSValuePtr, const ArgList&);
static JSValuePtr arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JSValuePtr, const ArgList&);
}
......@@ -107,6 +108,7 @@ const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::a
lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1
filter arrayProtoFuncFilter DontEnum|Function 1
reduce arrayProtoFuncReduce DontEnum|Function 1
reduceRight arrayProtoFuncReduceRight DontEnum|Function 1
map arrayProtoFuncMap DontEnum|Function 1
@end
*/
......@@ -843,6 +845,75 @@ JSValuePtr arrayProtoFuncReduce(ExecState* exec, JSObject*, JSValuePtr thisValue
return rv;
}
JSValuePtr arrayProtoFuncReduceRight(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args)
{
JSObject* thisObj = thisValue.toThisObject(exec);
JSValuePtr function = args.at(exec, 0);
CallData callData;
CallType callType = function.getCallData(callData);
if (callType == CallTypeNone)
return throwError(exec, TypeError);
unsigned i = 0;
JSValuePtr rv;
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
if (!length && args.size() == 1)
return throwError(exec, TypeError);
JSArray* array = 0;
if (isJSArray(&exec->globalData(), thisObj))
array = asArray(thisObj);
if (args.size() >= 2)
rv = args.at(exec, 1);
else if (array && array->canGetIndex(length - 1)){
rv = array->getIndex(length - 1);
i = 1;
} else {
for (i = 0; i < length; i++) {
rv = getProperty(exec, thisObj, length - i - 1);
if (rv)
break;
}
if (!rv)
return throwError(exec, TypeError);
i++;
}
if (callType == CallTypeJS && array) {
CachedCall cachedCall(exec, asFunction(function), 4, exec->exceptionSlot());
for (; i < length && !exec->hadException(); ++i) {
unsigned idx = length - i - 1;
cachedCall.setThis(jsNull());
cachedCall.setArgument(0, rv);
if (UNLIKELY(!array->canGetIndex(idx)))
break; // length has been made unsafe while we enumerate fallback to slow path
cachedCall.setArgument(1, array->getIndex(idx));
cachedCall.setArgument(2, jsNumber(exec, idx));
cachedCall.setArgument(3, array);
rv = cachedCall.call();
}
if (i == length) // only return if we reached the end of the array
return rv;
}
for (; i < length && !exec->hadException(); ++i) {
unsigned idx = length - i - 1;
JSValuePtr prop = getProperty(exec, thisObj, idx);
if (!prop)
continue;
ArgList eachArguments;
eachArguments.append(rv);
eachArguments.append(prop);
eachArguments.append(jsNumber(exec, idx));
eachArguments.append(thisObj);
rv = call(exec, function, callType, callData, jsNull(), eachArguments);
}
return rv;
}
JSValuePtr arrayProtoFuncIndexOf(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args)
{
// JavaScript 1.5 Extension by Mozilla
......
2009-04-15 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
Bug 25229: Need support for Array.prototype.reduceRight
<https://bugs.webkit.org/show_bug.cgi?id=25229>
Add test coverage for Array.reduceRight
* fast/js/array-enumerators-functions-expected.txt:
* fast/js/array-reduceRight-expected.txt: Added.
* fast/js/array-reduceRight.html: Added.
* fast/js/resources/array-enumerators-functions.js:
* fast/js/resources/array-reduceRight.js: Added.
2009-04-15 Oliver Hunt <oliver@apple.com>
Reviewed by Gavin Barraclough.
......
This test checks the behavior of the reduceRight() method on a number of objects.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS [0,1,2,3].reduceRight(function(a,b){ return a + b; }) is 6
PASS [1,2,3].reduceRight(function(a,b){ return a + b; }) is 6
PASS [0,1,2,3].reduceRight(function(a,b){ return a + b; }, 4) is 10
PASS [1,2,3].reduceRight(function(a,b){ return a + b; }, 4) is 10
PASS toObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; }) is 6
PASS toObject([1,2,3]).reduceRight(function(a,b){ return a + b; }) is 6
PASS toObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; }, 4) is 10
PASS toObject([1,2,3]).reduceRight(function(a,b){ return a + b; }, 4) is 10
PASS toUnorderedObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; }) is 6
PASS toUnorderedObject([1,2,3]).reduceRight(function(a,b){ return a + b; }) is 6
PASS toUnorderedObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; }, 4) is 10
PASS toUnorderedObject([1,2,3]).reduceRight(function(a,b){ return a + b; }, 4) is 10
PASS sparseArray.reduceRight(function(a,b){ return a + b; }, 0) is 10
PASS toObject(sparseArray).reduceRight(function(a,b){ return a + b; }, 0) is 10
PASS sparseArray.reduceRight(function(a,b){ callCount++; }); callCount is 0
PASS toObject(sparseArray).reduceRight(function(a,b){ callCount++; }); callCount is 0
PASS sparseArray.reduceRight(function(a,b){ callCount++; }, 0); callCount is 1
PASS toObject(sparseArray).reduceRight(function(a,b){ callCount++; }, 0); callCount is 1
PASS [0,1,2,3,4].reduceRight(function(a,b){ callCount++; }, 0); callCount is 5
PASS [0,1,2,3,4].reduceRight(function(a,b){ callCount++; }); callCount is 4
PASS [1, 2, 3, 4].reduceRight(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount is 4
PASS [1, 2, 3, 4].reduceRight(function(a,b, i, thisObj){ thisObj.length = 1; callCount++; return a + b; }, 0); callCount is 2
PASS [1, 2, 3, 4].reduceRight(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount is 4
PASS toObject([1, 2, 3, 4]).reduceRight(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount is 4
PASS toObject([1, 2, 3, 4]).reduceRight(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount is 4
PASS [[0,1], [2,3], [4,5]].reduceRight(function(a,b) {return a.concat(b);}, []) is [4,5,2,3,0,1]
PASS toObject([[0,1], [2,3], [4,5]]).reduceRight(function(a,b) {return a.concat(b);}, []) is [4,5,2,3,0,1]
PASS toObject([0,1,2,3,4,5]).reduceRight(function(a,b,i) {return a.concat([i,b]);}, []) is [5,5,4,4,3,3,2,2,1,1,0,0]
PASS toUnorderedObject([[0,1], [2,3], [4,5]]).reduceRight(function(a,b) {return a.concat(b);}, []) is [4,5,2,3,0,1]
PASS toUnorderedObject([0,1,2,3,4,5]).reduceRight(function(a,b,i) {return a.concat([i,b]);}, []) is [5,5,4,4,3,3,2,2,1,1,0,0]
PASS [0,1,2,3,4,5].reduceRight(function(a,b,i) {return a.concat([i,b]);}, []) is [5,5,4,4,3,3,2,2,1,1,0,0]
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="resources/array-reduceRight.js"></script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
......@@ -2,14 +2,15 @@ description(
"This test checks the behavior of the various array enumeration functions in certain edge case scenarios"
);
var functions = ["every", "forEach", "some", "filter", "reduce", "map"];
var functions = ["every", "forEach", "some", "filter", "reduce", "map", "reduceRight"];
var forwarders = [
function(elem, index, array) { return currentFunc.call(this, elem, index, array); },
function(elem, index, array) { return currentFunc.call(this, elem, index, array); },
function(elem, index, array) { return currentFunc.call(this, elem, index, array); },
function(elem, index, array) { return currentFunc.call(this, elem, index, array); },
function(prev, elem, index, array) { return currentFunc.call(this, elem, index, array); },
function(elem, index, array) { return currentFunc.call(this, elem, index, array); }
function(elem, index, array) { return currentFunc.call(this, elem, index, array); },
function(prev, elem, index, array) { return currentFunc.call(this, elem, index, array); }
];
function toObject(array) {
......@@ -35,8 +36,9 @@ function returnElem(elem) { count++; return elem; }
function returnIndex(a, index) { if (lastIndex >= index) throw "Unordered traversal"; lastIndex = index; count++; return index; }
function increaseLength(a, b, array) { count++; array.length++; }
function decreaseLength(a, b, array) { count++; array.length--; }
function halveLength(a, b, array) { count++; if (!array.halved) array.length = (array.length / 2) | 0; array.halved = true; }
var testFunctions = ["returnFalse", "returnTrue", "returnElem", "returnIndex", "increaseLength", "decreaseLength"];
var testFunctions = ["returnFalse", "returnTrue", "returnElem", "returnIndex", "increaseLength", "decreaseLength", "halveLength"];
var simpleArray = [0,1,2,3,4,5];
var emptyArray = [];
......@@ -60,6 +62,8 @@ for (var f = 0; f < functions.length; f++) {
currentFunc = this[testFunctions[t]];
if (arrays[a] === "largeEmptyArray" && functionName === "map")
continue;
if (currentFunc === returnIndex && functionName === "reduceRight")
continue;
shouldBe("count=0;lastIndex=-1;copyArray("+arrays[a]+")."+functionName+"(forwarders[f], "+testFunctions[t]+", 0)",
"count=0;lastIndex=-1;Array.prototype."+functionName+".call(toObject("+arrays[a]+"), forwarders[f], "+testFunctions[t]+", 0)");
}
......@@ -74,6 +78,8 @@ for (var f = 0; f < functions.length; f++) {
currentFunc = this[testFunctions[t]];
if (arrays[a] === "largeEmptyArray" && functionName === "map")
continue;
if (currentFunc === returnIndex && functionName === "reduceRight")
continue;
shouldBe("count=0;lastIndex=-1;copyArray("+arrays[a]+")."+functionName+"(forwarders[f], "+testFunctions[t]+", 0)",
"count=0;lastIndex=-1;Array.prototype."+functionName+".call(toUnorderedObject("+arrays[a]+"), forwarders[f], "+testFunctions[t]+", 0)");
}
......@@ -82,26 +88,30 @@ for (var f = 0; f < functions.length; f++) {
// Test number of function calls
var callCounts = [
[[1,0,0,1],[6,0,0,7],[1,0,0,1],[1,0,0,1],[1,0,0,1],[1,0,0,1]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6]],
[[6,0,0,7],[1,0,0,1],[2,0,0,2],[2,0,0,2],[6,0,0,7],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6]]
];
var objCallCounts = [
[[1,0,0,1],[6,0,0,7],[1,0,0,1],[1,0,0,1],[1,0,0,1],[1,0,0,1]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[1,0,0,1],[2,0,0,2],[2,0,0,2],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]]
[[1,0,0,1],[6,0,0,7],[1,0,0,1],[1,0,0,1],[1,0,0,1],[1,0,0,1],[1,0,0,1]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6],[3,0,0,6]],
[[6,0,0,7],[1,0,0,1],[2,0,0,2],[2,0,0,2],[6,0,0,7],[3,0,0,6],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[3,0,0,6],[3,0,0,6]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[4,0,0,7]]
];
var objCallCounts = [
[[1,0,0,1],[6,0,0,7],[1,0,0,1],[1,0,0,1],[1,0,0,1],[1,0,0,1],[1,0,0,1]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[1,0,0,1],[2,0,0,2],[2,0,0,2],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]],
[[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7],[6,0,0,7]]
];
for (var f = 0; f < functions.length; f++) {
for (var t = 0; t < testFunctions.length; t++) {
for (var a = 0; a < arrays.length; a++) {
var functionName = functions[f];
currentFunc = this[testFunctions[t]];
if (currentFunc === returnIndex && functionName === "reduceRight")
continue;
var expectedCnt = "" + callCounts[f][t][a];
shouldBe("count=0;lastIndex=-1;copyArray("+arrays[a]+")."+functionName+"(forwarders[f], "+testFunctions[t]+", 0); count", expectedCnt);
var expectedCnt = "" + objCallCounts[f][t][a];
......
description(
"This test checks the behavior of the reduceRight() method on a number of objects."
);
function toObject(array) {
var o = {};
for (var i in array)
o[i] = array[i];
o.length = array.length;
o.reduceRight = Array.prototype.reduceRight;
return o;
}
function toUnorderedObject(array) {
var o = {};
var props = [];
for (var i in array)
props.push(i);
for (var i = props.length - 1; i >= 0; i--)
o[props[i]] = array[props[i]];
o.length = array.length;
o.reduceRight = Array.prototype.reduceRight;
return o;
}
shouldBe("[0,1,2,3].reduceRight(function(a,b){ return a + b; })", "6");
shouldBe("[1,2,3].reduceRight(function(a,b){ return a + b; })", "6");
shouldBe("[0,1,2,3].reduceRight(function(a,b){ return a + b; }, 4)", "10");
shouldBe("[1,2,3].reduceRight(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; })", "6");
shouldBe("toObject([1,2,3]).reduceRight(function(a,b){ return a + b; })", "6");
shouldBe("toObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toObject([1,2,3]).reduceRight(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toUnorderedObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; })", "6");
shouldBe("toUnorderedObject([1,2,3]).reduceRight(function(a,b){ return a + b; })", "6");
shouldBe("toUnorderedObject([0,1,2,3]).reduceRight(function(a,b){ return a + b; }, 4)", "10");
shouldBe("toUnorderedObject([1,2,3]).reduceRight(function(a,b){ return a + b; }, 4)", "10");
sparseArray = [];
sparseArray[10] = 10;
shouldBe("sparseArray.reduceRight(function(a,b){ return a + b; }, 0)", "10");
shouldBe("toObject(sparseArray).reduceRight(function(a,b){ return a + b; }, 0)", "10");
var callCount = 0;
shouldBe("sparseArray.reduceRight(function(a,b){ callCount++; }); callCount", "0");
callCount = 0;
shouldBe("toObject(sparseArray).reduceRight(function(a,b){ callCount++; }); callCount", "0");
var callCount = 0;
shouldBe("sparseArray.reduceRight(function(a,b){ callCount++; }, 0); callCount", "1");
callCount = 0;
shouldBe("toObject(sparseArray).reduceRight(function(a,b){ callCount++; }, 0); callCount", "1");
callCount = 0;
shouldBe("[0,1,2,3,4].reduceRight(function(a,b){ callCount++; }, 0); callCount", "5");
callCount = 0;
shouldBe("[0,1,2,3,4].reduceRight(function(a,b){ callCount++; }); callCount", "4");
callCount = 0;
shouldBe("[1, 2, 3, 4].reduceRight(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount", "4");
callCount = 0;
shouldBe("[1, 2, 3, 4].reduceRight(function(a,b, i, thisObj){ thisObj.length = 1; callCount++; return a + b; }, 0); callCount", "2");
callCount = 0;
shouldBe("[1, 2, 3, 4].reduceRight(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount", "4");
callCount = 0;
shouldBe("toObject([1, 2, 3, 4]).reduceRight(function(a,b, i, thisObj){ thisObj.length--; callCount++; return a + b; }, 0); callCount", "4");
callCount = 0;
shouldBe("toObject([1, 2, 3, 4]).reduceRight(function(a,b, i, thisObj){ thisObj.length++; callCount++; return a + b; }, 0); callCount", "4");
shouldBe("[[0,1], [2,3], [4,5]].reduceRight(function(a,b) {return a.concat(b);}, [])", "[4,5,2,3,0,1]");
shouldBe("toObject([[0,1], [2,3], [4,5]]).reduceRight(function(a,b) {return a.concat(b);}, [])", "[4,5,2,3,0,1]");
shouldBe("toObject([0,1,2,3,4,5]).reduceRight(function(a,b,i) {return a.concat([i,b]);}, [])", "[5,5,4,4,3,3,2,2,1,1,0,0]");
shouldBe("toUnorderedObject([[0,1], [2,3], [4,5]]).reduceRight(function(a,b) {return a.concat(b);}, [])", "[4,5,2,3,0,1]");
shouldBe("toUnorderedObject([0,1,2,3,4,5]).reduceRight(function(a,b,i) {return a.concat([i,b]);}, [])", "[5,5,4,4,3,3,2,2,1,1,0,0]");
shouldBe("[0,1,2,3,4,5].reduceRight(function(a,b,i) {return a.concat([i,b]);}, [])", "[5,5,4,4,3,3,2,2,1,1,0,0]");
successfullyParsed = true;
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