michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef builtin_MapObject_h michael@0: #define builtin_MapObject_h michael@0: michael@0: #include "jsobj.h" michael@0: michael@0: #include "vm/Runtime.h" michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Comparing two ropes for equality can fail. The js::HashTable template michael@0: * requires infallible hash() and match() operations. Therefore we require michael@0: * all values to be converted to hashable form before being used as a key michael@0: * in a Map or Set object. michael@0: * michael@0: * All values except ropes are hashable as-is. michael@0: */ michael@0: class HashableValue { michael@0: EncapsulatedValue value; michael@0: michael@0: public: michael@0: struct Hasher { michael@0: typedef HashableValue Lookup; michael@0: static HashNumber hash(const Lookup &v) { return v.hash(); } michael@0: static bool match(const HashableValue &k, const Lookup &l) { return k == l; } michael@0: static bool isEmpty(const HashableValue &v) { return v.value.isMagic(JS_HASH_KEY_EMPTY); } michael@0: static void makeEmpty(HashableValue *vp) { vp->value = MagicValue(JS_HASH_KEY_EMPTY); } michael@0: }; michael@0: michael@0: HashableValue() : value(UndefinedValue()) {} michael@0: michael@0: bool setValue(JSContext *cx, HandleValue v); michael@0: HashNumber hash() const; michael@0: bool operator==(const HashableValue &other) const; michael@0: HashableValue mark(JSTracer *trc) const; michael@0: Value get() const { return value.get(); } michael@0: }; michael@0: michael@0: class AutoHashableValueRooter : private AutoGCRooter michael@0: { michael@0: public: michael@0: explicit AutoHashableValueRooter(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : AutoGCRooter(cx, HASHABLEVALUE) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: bool setValue(JSContext *cx, HandleValue v) { michael@0: return value.setValue(cx, v); michael@0: } michael@0: michael@0: operator const HashableValue & () { michael@0: return value; michael@0: } michael@0: michael@0: friend void AutoGCRooter::trace(JSTracer *trc); michael@0: void trace(JSTracer *trc); michael@0: michael@0: private: michael@0: HashableValue value; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: template michael@0: class OrderedHashMap; michael@0: michael@0: template michael@0: class OrderedHashSet; michael@0: michael@0: typedef OrderedHashMap ValueMap; michael@0: michael@0: typedef OrderedHashSet ValueSet; michael@0: michael@0: class MapObject : public JSObject { michael@0: public: michael@0: enum IteratorKind { Keys, Values, Entries }; michael@0: michael@0: static JSObject *initClass(JSContext *cx, JSObject *obj); michael@0: static const Class class_; michael@0: private: michael@0: static const JSPropertySpec properties[]; michael@0: static const JSFunctionSpec methods[]; michael@0: ValueMap *getData() { return static_cast(getPrivate()); } michael@0: static ValueMap & extract(CallReceiver call); michael@0: static void mark(JSTracer *trc, JSObject *obj); michael@0: static void finalize(FreeOp *fop, JSObject *obj); michael@0: static bool construct(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: static bool is(HandleValue v); michael@0: michael@0: static bool iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind); michael@0: michael@0: static bool size_impl(JSContext *cx, CallArgs args); michael@0: static bool size(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool get_impl(JSContext *cx, CallArgs args); michael@0: static bool get(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool has_impl(JSContext *cx, CallArgs args); michael@0: static bool has(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool set_impl(JSContext *cx, CallArgs args); michael@0: static bool set(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool delete_impl(JSContext *cx, CallArgs args); michael@0: static bool delete_(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool keys_impl(JSContext *cx, CallArgs args); michael@0: static bool keys(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool values_impl(JSContext *cx, CallArgs args); michael@0: static bool values(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool entries_impl(JSContext *cx, CallArgs args); michael@0: static bool entries(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool clear_impl(JSContext *cx, CallArgs args); michael@0: static bool clear(JSContext *cx, unsigned argc, Value *vp); michael@0: }; michael@0: michael@0: class SetObject : public JSObject { michael@0: public: michael@0: enum IteratorKind { Values, Entries }; michael@0: static JSObject *initClass(JSContext *cx, JSObject *obj); michael@0: static const Class class_; michael@0: private: michael@0: static const JSPropertySpec properties[]; michael@0: static const JSFunctionSpec methods[]; michael@0: ValueSet *getData() { return static_cast(getPrivate()); } michael@0: static ValueSet & extract(CallReceiver call); michael@0: static void mark(JSTracer *trc, JSObject *obj); michael@0: static void finalize(FreeOp *fop, JSObject *obj); michael@0: static bool construct(JSContext *cx, unsigned argc, Value *vp); michael@0: michael@0: static bool is(HandleValue v); michael@0: michael@0: static bool iterator_impl(JSContext *cx, CallArgs args, IteratorKind kind); michael@0: michael@0: static bool size_impl(JSContext *cx, CallArgs args); michael@0: static bool size(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool has_impl(JSContext *cx, CallArgs args); michael@0: static bool has(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool add_impl(JSContext *cx, CallArgs args); michael@0: static bool add(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool delete_impl(JSContext *cx, CallArgs args); michael@0: static bool delete_(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool values_impl(JSContext *cx, CallArgs args); michael@0: static bool values(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool entries_impl(JSContext *cx, CallArgs args); michael@0: static bool entries(JSContext *cx, unsigned argc, Value *vp); michael@0: static bool clear_impl(JSContext *cx, CallArgs args); michael@0: static bool clear(JSContext *cx, unsigned argc, Value *vp); michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern JSObject * michael@0: js_InitMapClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: extern JSObject * michael@0: js_InitSetClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: #endif /* builtin_MapObject_h */