Bug 817368 - Map.prototype.{keys,values,entries}. r=luke.

--HG--
extra : rebase_source : c802c900efe40c7204747519868051e9fa085e99
This commit is contained in:
Jason Orendorff 2012-12-14 14:33:13 -06:00
Родитель 4dc4213e81
Коммит 3814213457
6 изменённых файлов: 121 добавлений и 21 удалений

Просмотреть файл

@ -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 */