зеркало из https://github.com/mozilla/gecko-dev.git
Bug 866847 - Implement map#forEach and Set#forEach. r=evilpie
This commit is contained in:
Родитель
63736e952d
Коммит
245df3eac1
|
@ -642,6 +642,8 @@ selfhosting_srcs := \
|
|||
$(srcdir)/builtin/Number.js \
|
||||
$(srcdir)/builtin/ParallelArray.js \
|
||||
$(srcdir)/builtin/String.js \
|
||||
$(srcdir)/builtin/Set.js \
|
||||
$(srcdir)/builtin/Map.js \
|
||||
$(NULL)
|
||||
|
||||
selfhosted_out_h_deps := \
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* ES6 20121122 draft 15.14.4.4. */
|
||||
|
||||
function MapForEach(callbackfn, thisArg = undefined) {
|
||||
/* Step 1-2. */
|
||||
var M = this;
|
||||
if (!IsObject(M))
|
||||
ThrowError(JSMSG_BAD_TYPE, typeof M);
|
||||
|
||||
/* Step 3-4. */
|
||||
try {
|
||||
std_Map_has.call(M);
|
||||
} catch (e) {
|
||||
ThrowError(JSMSG_BAD_TYPE, typeof M);
|
||||
}
|
||||
|
||||
/* Step 5. */
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
|
||||
|
||||
/* Step 6-8. */
|
||||
var entries = std_Map_iterator.call(M);
|
||||
while (true) {
|
||||
try {
|
||||
var entry = std_Map_iterator_next.call(entries);
|
||||
} catch (err) {
|
||||
if (err instanceof StopIteration)
|
||||
break;
|
||||
throw err;
|
||||
}
|
||||
callFunction(callbackfn, thisArg, entry[1], entry[0], M);
|
||||
}
|
||||
}
|
|
@ -1036,6 +1036,7 @@ const JSFunctionSpec MapObject::methods[] = {
|
|||
JS_FN("keys", keys, 0, 0),
|
||||
JS_FN("values", values, 0, 0),
|
||||
JS_FN("clear", clear, 0, 0),
|
||||
{"forEach", {NULL, NULL}, 2, 0, "MapForEach"},
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -1592,6 +1593,7 @@ const JSFunctionSpec SetObject::methods[] = {
|
|||
JS_FN("delete", delete_, 1, 0),
|
||||
JS_FN("entries", entries, 0, 0),
|
||||
JS_FN("clear", clear, 0, 0),
|
||||
{"forEach", {NULL, NULL}, 2, 0, "SetForEach"},
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* ES6 20121122 draft 15.16.4.6. */
|
||||
|
||||
function SetForEach(callbackfn, thisArg = undefined) {
|
||||
/* Step 1-2. */
|
||||
var S = this;
|
||||
if (!IsObject(S))
|
||||
ThrowError(JSMSG_BAD_TYPE, typeof S);
|
||||
|
||||
/* Step 3-4. */
|
||||
try {
|
||||
std_Set_has.call(S);
|
||||
} catch (e) {
|
||||
ThrowError(JSMSG_BAD_TYPE, typeof S);
|
||||
}
|
||||
|
||||
/* Step 5-6. */
|
||||
if (!IsCallable(callbackfn))
|
||||
ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
|
||||
|
||||
/* Step 7-8. */
|
||||
var values = std_Set_iterator.call(S);
|
||||
while (true) {
|
||||
try {
|
||||
var entry = std_Set_iterator_next.call(values);
|
||||
} catch (err) {
|
||||
if (err instanceof StopIteration)
|
||||
break;
|
||||
throw err;
|
||||
}
|
||||
callFunction(callbackfn, thisArg, entry, entry, S);
|
||||
}
|
||||
}
|
|
@ -73,7 +73,12 @@ var std_String_toUpperCase = String.prototype.toUpperCase;
|
|||
var std_WeakMap_get = WeakMap.prototype.get;
|
||||
var std_WeakMap_has = WeakMap.prototype.has;
|
||||
var std_WeakMap_set = WeakMap.prototype.set;
|
||||
|
||||
var std_Map_has = Map.prototype.has;
|
||||
var std_Set_has = Set.prototype.has;
|
||||
var std_Map_iterator = Map().iterator;
|
||||
var std_Set_iterator = Set().iterator;
|
||||
var std_Map_iterator_next = Object.getPrototypeOf(Map().iterator()).next;
|
||||
var std_Set_iterator_next = Object.getPrototypeOf(Set().iterator()).next;
|
||||
|
||||
/********** List specification type **********/
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* test Map.prototype.forEach */
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
// testing success conditions of Map.prototype.forEach
|
||||
|
||||
var testMap = new Map();
|
||||
|
||||
function callback(value, key, map) {
|
||||
testMap.set(key, value);
|
||||
assertEq(map.has(key), true);
|
||||
assertEq(map.get(key), value);
|
||||
}
|
||||
|
||||
var initialMap = new Map([['a', 1], ['b', 2.3], [false, undefined]]);
|
||||
initialMap.forEach(callback);
|
||||
|
||||
// test that both the Maps are equal and are in same order
|
||||
var iterator = initialMap.iterator();
|
||||
var count = 0;
|
||||
for (var [k, v] of testMap) {
|
||||
assertEq(initialMap.has(k), true);
|
||||
assertEq(initialMap.get(k), testMap.get(k));
|
||||
assertEq(iterator.next()[1], testMap.get(k));
|
||||
count++;
|
||||
}
|
||||
|
||||
//check both the Maps we have are equal in size
|
||||
assertEq(initialMap.size, testMap.size);
|
||||
assertEq(initialMap.size, count);
|
||||
|
||||
var x = { abc: 'test'};
|
||||
function callback2(value, key, map) {
|
||||
assertEq(x, this);
|
||||
}
|
||||
initialMap = new Map([['a', 1]]);
|
||||
initialMap.forEach(callback2, x);
|
||||
|
||||
// testing failure conditions of Map.prototype.forEach
|
||||
|
||||
var s = new Set([1, 2, 3]);
|
||||
assertThrowsInstanceOf(function() {
|
||||
Map.prototype.forEach.call(s, callback);
|
||||
}, TypeError, "Map.prototype.forEach should raise TypeError if not used on a Map");
|
||||
|
||||
var fn = 2;
|
||||
assertThrowsInstanceOf(function() {
|
||||
initialMap.forEach(fn);
|
||||
}, TypeError, "Map.prototype.forEach should raise TypeError if callback is not a function");
|
||||
|
||||
// testing that Map#forEach uses internal next() function and does not stop when
|
||||
// StopIteration exception is thrown
|
||||
|
||||
var m = new Map([["one", 1]]);
|
||||
Object.getPrototypeOf(m.iterator()).next = function () { throw "FAIL"; };
|
||||
assertThrowsInstanceOf(function () {
|
||||
m.forEach(function () { throw StopIteration; });
|
||||
}, StopIteration, "Map.prototype.forEach should use intrinsic next method.");
|
|
@ -0,0 +1,57 @@
|
|||
/* test Set.prototype.forEach */
|
||||
|
||||
load(libdir + 'asserts.js');
|
||||
|
||||
// testing success conditions of Set.prototype.forEach
|
||||
|
||||
var testSet = new Set();
|
||||
|
||||
function callback(value, key, set) {
|
||||
assertEq(value, key);
|
||||
testSet.add(value);
|
||||
assertEq(set.has(key), true);
|
||||
}
|
||||
|
||||
var initialSet = new Set(['a', 1, undefined]);
|
||||
initialSet.forEach(callback);
|
||||
|
||||
// test that both the Sets are equal and are in same order
|
||||
var iterator = initialSet.iterator();
|
||||
var count = 0;
|
||||
for (var v of testSet) {
|
||||
assertEq(initialSet.has(v), true);
|
||||
assertEq(iterator.next(), v);
|
||||
count++;
|
||||
}
|
||||
|
||||
//check both the Sets we have are equal in size
|
||||
assertEq(initialSet.size, testSet.size);
|
||||
assertEq(initialSet.size, count);
|
||||
|
||||
var x = { abc: 'test'};
|
||||
function callback2(value, key, set) {
|
||||
assertEq(x, this);
|
||||
}
|
||||
initialSet = new Set(['a']);
|
||||
initialSet.forEach(callback2, x);
|
||||
|
||||
// testing failure conditions of Set.prototype.forEach
|
||||
|
||||
var m = new Map([['a', 1], ['b', 2.3], ['c', undefined]]);
|
||||
assertThrowsInstanceOf(function() {
|
||||
Set.prototype.forEach.call(m, callback);
|
||||
}, TypeError, "Set.prototype.forEach should raise TypeError if not a used on a Set");
|
||||
|
||||
var fn = 2;
|
||||
assertThrowsInstanceOf(function() {
|
||||
initialSet.forEach(fn);
|
||||
}, TypeError, "Set.prototype.forEach should raise TypeError if callback is not a function");
|
||||
|
||||
// testing that Set#forEach uses internal next() function and does not stop when
|
||||
// StopIteration exception is thrown
|
||||
|
||||
var s = new Set(["one", 1]);
|
||||
Object.getPrototypeOf(s.iterator()).next = function () { throw "FAIL"; };
|
||||
assertThrowsInstanceOf(function () {
|
||||
s.forEach(function () { throw StopIteration; });
|
||||
}, StopIteration, "Set.prototype.forEach should use intrinsic next method.");
|
Загрузка…
Ссылка в новой задаче