зеркало из 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/Number.js \
|
||||||
$(srcdir)/builtin/ParallelArray.js \
|
$(srcdir)/builtin/ParallelArray.js \
|
||||||
$(srcdir)/builtin/String.js \
|
$(srcdir)/builtin/String.js \
|
||||||
|
$(srcdir)/builtin/Set.js \
|
||||||
|
$(srcdir)/builtin/Map.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
selfhosted_out_h_deps := \
|
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("keys", keys, 0, 0),
|
||||||
JS_FN("values", values, 0, 0),
|
JS_FN("values", values, 0, 0),
|
||||||
JS_FN("clear", clear, 0, 0),
|
JS_FN("clear", clear, 0, 0),
|
||||||
|
{"forEach", {NULL, NULL}, 2, 0, "MapForEach"},
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1592,6 +1593,7 @@ const JSFunctionSpec SetObject::methods[] = {
|
||||||
JS_FN("delete", delete_, 1, 0),
|
JS_FN("delete", delete_, 1, 0),
|
||||||
JS_FN("entries", entries, 0, 0),
|
JS_FN("entries", entries, 0, 0),
|
||||||
JS_FN("clear", clear, 0, 0),
|
JS_FN("clear", clear, 0, 0),
|
||||||
|
{"forEach", {NULL, NULL}, 2, 0, "SetForEach"},
|
||||||
JS_FS_END
|
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_get = WeakMap.prototype.get;
|
||||||
var std_WeakMap_has = WeakMap.prototype.has;
|
var std_WeakMap_has = WeakMap.prototype.has;
|
||||||
var std_WeakMap_set = WeakMap.prototype.set;
|
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 **********/
|
/********** 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.");
|
Загрузка…
Ссылка в новой задаче