зеркало из https://github.com/mozilla/gecko-dev.git
Bug 817368 - Map.prototype.{keys,values,entries}. r=luke.
--HG-- extra : rebase_source : c802c900efe40c7204747519868051e9fa085e99
This commit is contained in:
Родитель
4dc4213e81
Коммит
3814213457
|
@ -793,14 +793,16 @@ HashableValue::mark(JSTracer *trc) const
|
|||
class js::MapIteratorObject : public JSObject
|
||||
{
|
||||
public:
|
||||
enum { TargetSlot, RangeSlot, SlotCount };
|
||||
enum { TargetSlot, KindSlot, RangeSlot, SlotCount };
|
||||
static JSFunctionSpec methods[];
|
||||
static MapIteratorObject *create(JSContext *cx, HandleObject mapobj, ValueMap *data);
|
||||
static MapIteratorObject *create(JSContext *cx, HandleObject mapobj, ValueMap *data,
|
||||
MapObject::IteratorKind kind);
|
||||
static void finalize(FreeOp *fop, RawObject obj);
|
||||
|
||||
private:
|
||||
static inline bool is(const Value &v);
|
||||
inline ValueMap::Range *range();
|
||||
inline MapObject::IteratorKind kind() const;
|
||||
static bool next_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool next(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
@ -813,7 +815,7 @@ JSObject::asMapIterator()
|
|||
}
|
||||
|
||||
Class js::MapIteratorClass = {
|
||||
"Iterator",
|
||||
"Map Iterator",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
|
@ -836,6 +838,14 @@ MapIteratorObject::range()
|
|||
return static_cast<ValueMap::Range *>(getSlot(RangeSlot).toPrivate());
|
||||
}
|
||||
|
||||
inline MapObject::IteratorKind
|
||||
MapIteratorObject::kind() const
|
||||
{
|
||||
int32_t i = getSlot(KindSlot).toInt32();
|
||||
JS_ASSERT(i == MapObject::Keys || i == MapObject::Values || i == MapObject::Entries);
|
||||
return MapObject::IteratorKind(i);
|
||||
}
|
||||
|
||||
bool
|
||||
GlobalObject::initMapIteratorProto(JSContext *cx, Handle<GlobalObject *> global)
|
||||
{
|
||||
|
@ -854,7 +864,8 @@ GlobalObject::initMapIteratorProto(JSContext *cx, Handle<GlobalObject *> global)
|
|||
}
|
||||
|
||||
MapIteratorObject *
|
||||
MapIteratorObject::create(JSContext *cx, HandleObject mapobj, ValueMap *data)
|
||||
MapIteratorObject::create(JSContext *cx, HandleObject mapobj, ValueMap *data,
|
||||
MapObject::IteratorKind kind)
|
||||
{
|
||||
Rooted<GlobalObject *> global(cx, &mapobj->global());
|
||||
Rooted<JSObject*> proto(cx, global->getOrCreateMapIteratorPrototype(cx));
|
||||
|
@ -871,6 +882,7 @@ MapIteratorObject::create(JSContext *cx, HandleObject mapobj, ValueMap *data)
|
|||
return NULL;
|
||||
}
|
||||
iterobj->setSlot(TargetSlot, ObjectValue(*mapobj));
|
||||
iterobj->setSlot(KindSlot, Int32Value(int32_t(kind)));
|
||||
iterobj->setSlot(RangeSlot, PrivateValue(range));
|
||||
return static_cast<MapIteratorObject *>(iterobj);
|
||||
}
|
||||
|
@ -900,14 +912,27 @@ MapIteratorObject::next_impl(JSContext *cx, CallArgs args)
|
|||
return js_ThrowStopIteration(cx);
|
||||
}
|
||||
|
||||
Value pair[2] = { range->front().key.get(), range->front().value };
|
||||
AutoValueArray root(cx, pair, 2);
|
||||
switch (thisobj.kind()) {
|
||||
case MapObject::Keys:
|
||||
args.rval().set(range->front().key.get());
|
||||
break;
|
||||
|
||||
JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
|
||||
if (!pairobj)
|
||||
return false;
|
||||
case MapObject::Values:
|
||||
args.rval().set(range->front().value);
|
||||
break;
|
||||
|
||||
case MapObject::Entries: {
|
||||
Value pair[2] = { range->front().key.get(), range->front().value };
|
||||
AutoValueArray root(cx, pair, 2);
|
||||
|
||||
JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
|
||||
if (!pairobj)
|
||||
return false;
|
||||
args.rval().setObject(*pairobj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
range->popFront();
|
||||
args.rval().setObject(*pairobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -957,7 +982,10 @@ JSFunctionSpec MapObject::methods[] = {
|
|||
JS_FN("has", has, 1, 0),
|
||||
JS_FN("set", set, 2, 0),
|
||||
JS_FN("delete", delete_, 1, 0),
|
||||
JS_FN("iterator", iterator, 0, 0),
|
||||
JS_FN("keys", keys, 0, 0),
|
||||
JS_FN("values", values, 0, 0),
|
||||
JS_FN("entries", entries, 0, 0),
|
||||
JS_FN("iterator", entries, 0, 0),
|
||||
JS_FN("clear", clear, 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
@ -1218,22 +1246,54 @@ MapObject::delete_(JSContext *cx, unsigned argc, Value *vp)
|
|||
}
|
||||
|
||||
bool
|
||||
MapObject::iterator_impl(JSContext *cx, CallArgs args)
|
||||
MapObject::iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind)
|
||||
{
|
||||
Rooted<MapObject*> mapobj(cx, &args.thisv().toObject().asMap());
|
||||
ValueMap &map = *mapobj->getData();
|
||||
Rooted<JSObject*> iterobj(cx, MapIteratorObject::create(cx, mapobj, &map));
|
||||
Rooted<JSObject*> iterobj(cx, MapIteratorObject::create(cx, mapobj, &map, kind));
|
||||
if (!iterobj)
|
||||
return false;
|
||||
args.rval().setObject(*iterobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::keys_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
return iterator_impl(cx, args, Keys);
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::iterator(JSContext *cx, unsigned argc, Value *vp)
|
||||
MapObject::keys(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, iterator_impl, args);
|
||||
return CallNonGenericMethod(cx, is, keys_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::values_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
return iterator_impl(cx, args, Values);
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::values(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, values_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
MapObject::entries_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
return iterator_impl(cx, args, Entries);
|
||||
}
|
||||
|
||||
JSBool
|
||||
MapObject::entries(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod(cx, is, entries_impl, args);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1287,7 +1347,7 @@ JSObject::asSetIterator()
|
|||
}
|
||||
|
||||
Class js::SetIteratorClass = {
|
||||
"Iterator",
|
||||
"Set Iterator",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_PropertyStub, /* delProperty */
|
||||
|
|
|
@ -81,6 +81,8 @@ typedef OrderedHashSet<HashableValue,
|
|||
|
||||
class MapObject : public JSObject {
|
||||
public:
|
||||
enum IteratorKind { Keys, Values, Entries };
|
||||
|
||||
static JSObject *initClass(JSContext *cx, JSObject *obj);
|
||||
static Class class_;
|
||||
private:
|
||||
|
@ -94,6 +96,8 @@ class MapObject : public JSObject {
|
|||
|
||||
static bool is(const Value &v);
|
||||
|
||||
static bool iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind);
|
||||
|
||||
static bool size_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool size(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool get_impl(JSContext *cx, CallArgs args);
|
||||
|
@ -104,8 +108,12 @@ class MapObject : public JSObject {
|
|||
static JSBool set(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool delete_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool iterator_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool iterator(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool keys_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool keys(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool values_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool values(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool entries_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool entries(JSContext *cx, unsigned argc, Value *vp);
|
||||
static bool clear_impl(JSContext *cx, CallArgs args);
|
||||
static JSBool clear(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// map.keys(), .values(), and .entries() on an empty map produce empty iterators.
|
||||
|
||||
var m = Map();
|
||||
var ki = m.keys(), vi = m.values(), ei = m.entries();
|
||||
var p = Object.getPrototypeOf(ki)
|
||||
assertEq(Object.getPrototypeOf(vi), p);
|
||||
assertEq(Object.getPrototypeOf(ei), p);
|
||||
|
||||
for (let k of ki)
|
||||
throw "FAIL";
|
||||
for (let v of vi)
|
||||
throw "FAIL";
|
||||
for (let [k, v] of ei)
|
||||
throw "FAIL";
|
|
@ -0,0 +1,18 @@
|
|||
// map.keys() and map.values() return iterators over the key or the value,
|
||||
// respectively, of each key-value pair in the map.
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
var data = [["one", 1], ["two", 2], ["three", 3], ["four", 4]];
|
||||
var m = Map(data);
|
||||
|
||||
var ki = m.keys();
|
||||
assertEq(ki.next(), "one");
|
||||
assertEq(ki.next(), "two");
|
||||
assertEq(ki.next(), "three");
|
||||
assertEq(ki.next(), "four");
|
||||
assertThrowsValue(function () { ki.next(); }, StopIteration);
|
||||
|
||||
assertEq([k for (k of m.keys())].toSource(), ["one", "two", "three", "four"].toSource());
|
||||
assertEq([k for (k of m.values())].toSource(), [1, 2, 3, 4].toSource());
|
||||
assertEq([k for (k of m.entries())].toSource(), data.toSource());
|
|
@ -1,10 +1,10 @@
|
|||
// collection.iterator() returns an Iterator object.
|
||||
|
||||
function test(obj) {
|
||||
function test(obj, name) {
|
||||
var iter = obj.iterator();
|
||||
assertEq(typeof iter, "object");
|
||||
assertEq(iter instanceof Iterator, true);
|
||||
assertEq(iter.toString(), "[object Iterator]");
|
||||
assertEq(iter.toString(), "[object " + obj.constructor.name + " Iterator]");
|
||||
}
|
||||
|
||||
test([]);
|
||||
|
|
|
@ -948,7 +948,7 @@ ElementIteratorObject::next_impl(JSContext *cx, CallArgs args)
|
|||
}
|
||||
|
||||
Class js::ElementIteratorClass = {
|
||||
"Iterator",
|
||||
"Array Iterator",
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ElementIteratorObject::NumSlots),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
|
|
Загрузка…
Ссылка в новой задаче