Commit 58479eef authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

jscript: Implement Set on top of Map.

Because a Set is just a Map where key == value. Signed-off-by: 's avatarGabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: 's avatarJacek Caban <jacek@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 15053a1d
...@@ -28,10 +28,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript); ...@@ -28,10 +28,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(jscript);
typedef struct { typedef struct {
jsdisp_t dispex; jsdisp_t dispex;
} SetInstance;
typedef struct {
jsdisp_t dispex;
struct wine_rb_tree map; struct wine_rb_tree map;
struct list entries; struct list entries;
size_t size; size_t size;
...@@ -105,6 +101,21 @@ static HRESULT get_map_this(jsval_t vthis, MapInstance **ret) ...@@ -105,6 +101,21 @@ static HRESULT get_map_this(jsval_t vthis, MapInstance **ret)
return S_OK; return S_OK;
} }
static HRESULT get_set_this(jsval_t vthis, MapInstance **ret)
{
jsdisp_t *jsdisp;
if(!is_object_instance(vthis))
return JS_E_OBJECT_EXPECTED;
if(!(jsdisp = to_jsdisp(get_object(vthis))) || !is_class(jsdisp, JSCLASS_SET)) {
WARN("not a Set object passed as 'this'\n");
return JS_E_MAP_EXPECTED;
}
*ret = CONTAINING_RECORD(jsdisp, MapInstance, dispex);
return S_OK;
}
static struct jsval_map_entry *get_map_entry(MapInstance *map, jsval_t key) static struct jsval_map_entry *get_map_entry(MapInstance *map, jsval_t key)
{ {
struct wine_rb_entry *entry; struct wine_rb_entry *entry;
...@@ -416,36 +427,91 @@ static HRESULT Map_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns ...@@ -416,36 +427,91 @@ static HRESULT Map_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
static HRESULT Set_add(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_add(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
FIXME("%p\n", debugstr_jsval(vthis)); jsval_t key = argc ? argv[0] : jsval_undefined();
return E_NOTIMPL; MapInstance *set;
HRESULT hres;
hres = get_set_this(vthis, &set);
if(FAILED(hres))
return hres;
TRACE("%p (%s)\n", set, debugstr_jsval(key));
return set_map_entry(set, key, key, r);
} }
static HRESULT Set_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_clear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
FIXME("%p\n", debugstr_jsval(vthis)); MapInstance *set;
return E_NOTIMPL; HRESULT hres;
hres = get_set_this(vthis, &set);
if(FAILED(hres))
return hres;
TRACE("%p\n", set);
while(!list_empty(&set->entries)) {
struct jsval_map_entry *entry = LIST_ENTRY(list_head(&set->entries), struct jsval_map_entry, list_entry);
delete_map_entry(set, entry);
}
if(r) *r = jsval_undefined();
return S_OK;
} }
static HRESULT Set_delete(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_delete(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
FIXME("%p\n", debugstr_jsval(vthis)); jsval_t key = argc ? argv[0] : jsval_undefined();
return E_NOTIMPL; struct jsval_map_entry *entry;
MapInstance *set;
HRESULT hres;
hres = get_set_this(vthis, &set);
if(FAILED(hres))
return hres;
TRACE("%p (%s)\n", set, debugstr_jsval(key));
if((entry = get_map_entry(set, key))) delete_map_entry(set, entry);
if(r) *r = jsval_bool(!!entry);
return S_OK;
} }
static HRESULT Set_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_forEach(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
FIXME("%p\n", debugstr_jsval(vthis)); MapInstance *set;
return E_NOTIMPL; HRESULT hres;
hres = get_set_this(vthis, &set);
if(FAILED(hres))
return hres;
TRACE("%p (%s)\n", set, debugstr_jsval(argc ? argv[0] : jsval_undefined()));
return iterate_map(set, ctx, argc, argv, r);
} }
static HRESULT Set_has(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_has(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
FIXME("%p\n", debugstr_jsval(vthis)); jsval_t key = argc ? argv[0] : jsval_undefined();
return E_NOTIMPL; struct jsval_map_entry *entry;
MapInstance *set;
HRESULT hres;
hres = get_set_this(vthis, &set);
if(FAILED(hres))
return hres;
TRACE("%p (%s)\n", set, debugstr_jsval(key));
entry = get_map_entry(set, key);
if(r) *r = jsval_bool(!!entry);
return S_OK;
} }
static HRESULT Set_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
...@@ -455,7 +521,7 @@ static HRESULT Set_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned ...@@ -455,7 +521,7 @@ static HRESULT Set_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned
return E_NOTIMPL; return E_NOTIMPL;
} }
static const builtin_prop_t Set_props[] = { static const builtin_prop_t Set_prototype_props[] = {
{L"add", Set_add, PROPF_METHOD|1}, {L"add", Set_add, PROPF_METHOD|1},
{L"clear", Set_clear, PROPF_METHOD}, {L"clear", Set_clear, PROPF_METHOD},
{L"delete" , Set_delete, PROPF_METHOD|1}, {L"delete" , Set_delete, PROPF_METHOD|1},
...@@ -464,10 +530,10 @@ static const builtin_prop_t Set_props[] = { ...@@ -464,10 +530,10 @@ static const builtin_prop_t Set_props[] = {
}; };
static const builtin_info_t Set_prototype_info = { static const builtin_info_t Set_prototype_info = {
JSCLASS_SET, JSCLASS_OBJECT,
Set_value, Set_value,
ARRAY_SIZE(Set_props), ARRAY_SIZE(Set_prototype_props),
Set_props, Set_prototype_props,
NULL, NULL,
NULL NULL
}; };
...@@ -475,15 +541,16 @@ static const builtin_info_t Set_prototype_info = { ...@@ -475,15 +541,16 @@ static const builtin_info_t Set_prototype_info = {
static const builtin_info_t Set_info = { static const builtin_info_t Set_info = {
JSCLASS_SET, JSCLASS_SET,
Set_value, Set_value,
0, NULL, ARRAY_SIZE(Map_props),
NULL, Map_props,
Map_destructor,
NULL NULL
}; };
static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
jsval_t *r) jsval_t *r)
{ {
SetInstance *set; MapInstance *set;
HRESULT hres; HRESULT hres;
switch(flags) { switch(flags) {
...@@ -499,6 +566,8 @@ static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns ...@@ -499,6 +566,8 @@ static HRESULT Set_constructor(script_ctx_t *ctx, jsval_t vthis, WORD flags, uns
if(FAILED(hres)) if(FAILED(hres))
return hres; return hres;
wine_rb_init(&set->map, jsval_map_compare);
list_init(&set->entries);
*r = jsval_obj(&set->dispex); *r = jsval_obj(&set->dispex);
return S_OK; return S_OK;
......
...@@ -912,6 +912,12 @@ sync_test("set_obj", function() { ...@@ -912,6 +912,12 @@ sync_test("set_obj", function() {
function test_length(name, len) { function test_length(name, len) {
ok(Set.prototype[name].length === len, "Set.prototype." + name + " = " + Set.prototype[name].length); ok(Set.prototype[name].length === len, "Set.prototype." + name + " = " + Set.prototype[name].length);
try {
Set.prototype[name].call({}, 0);
ok(false, "expected exception calling Set.prototype." + name + "(object)");
}catch(e) {
ok(e.number === 0xa13fc - 0x80000000, "Set.prototype." + name + "(object) threw " + e.number);
}
} }
test_length("add", 1); test_length("add", 1);
test_length("clear", 0); test_length("clear", 0);
...@@ -924,6 +930,65 @@ sync_test("set_obj", function() { ...@@ -924,6 +930,65 @@ sync_test("set_obj", function() {
r = Object.prototype.toString.call(s); r = Object.prototype.toString.call(s);
ok(r === "[object Object]", "toString returned " + r); ok(r === "[object Object]", "toString returned " + r);
r = s.has(-0);
ok(r === false, "has(-0) returned " + r);
ok(s.size === 0, "size = " + s.size);
r = s.add(42);
ok(r === undefined, "add(42) returned " + r);
r = s.add(42);
ok(r === undefined, "add(42) returned " + r);
r = s.add(0);
ok(r === undefined, "add(0) returned " + r);
r = s.has(-0);
ok(r === false, "has(-0) returned " + r);
r = s.add(-0);
ok(r === undefined, "add(-0) returned " + r);
r = s.has(-0);
ok(r === true, "has(-0) after add returned " + r);
r = s.add("test");
ok(r === undefined, "add(test) returned " + r);
r = s.add(13);
ok(r === undefined, "add(13) returned " + r);
r = s.add(s);
ok(r === undefined, "add(s) returned " + r);
r = s["delete"]("test"); /* using s.delete() would break parsing in quirks mode */
ok(r === true, "delete(test) returned " + r);
r = s["delete"]("test");
ok(r === false, "delete(test) returned " + r);
ok(s.size === 5, "size = " + s.size);
s.size = 100;
ok(s.size === 5, "size (after set) = " + s.size);
var a = [];
r = s.forEach(function(value, key, obj) {
var t = s["delete"](key);
ok(t === true, "delete(" + key + ") returned " + r);
ok(value === key, "value = " + value + ", key = " + key);
ok(obj === s, "set = " + obj);
ok(this === a, "this = " + this);
a.push(value);
}, a);
ok(r === undefined, "forEach returned " + r);
ok(a.length === 5, "a.length = " + a.length);
for(var i = 0; i < a.length; i++)
ok(a[i] === [42, 0, -0, 13, s][i], "a[" + i + "] = " + a[i]);
ok(s.size === 0, "size = " + s.size);
s = new Set();
ok(s.size === 0, "size = " + s.size);
s.add(1);
s.add(2);
ok(s.size === 2, "size = " + s.size);
r = s.clear();
ok(r === undefined, "clear returned " + r);
ok(s.size === 0, "size = " + s.size);
s = new Set([1, 2, 3]);
ok(s.size === 0, "size = " + s.size);
}); });
sync_test("map_obj", function() { sync_test("map_obj", function() {
......
...@@ -1376,6 +1376,7 @@ sync_test("builtin_context", function() { ...@@ -1376,6 +1376,7 @@ sync_test("builtin_context", function() {
[ "Number.toFixed", JS_E_NUMBER_EXPECTED, function(ctx) { Number.prototype.toFixed.call(ctx); } ], [ "Number.toFixed", JS_E_NUMBER_EXPECTED, function(ctx) { Number.prototype.toFixed.call(ctx); } ],
[ "Object.isPrototypeOf", JS_E_OBJECT_EXPECTED, function(ctx) { Object.prototype.isPrototypeOf.call(ctx, Object); } ], [ "Object.isPrototypeOf", JS_E_OBJECT_EXPECTED, function(ctx) { Object.prototype.isPrototypeOf.call(ctx, Object); } ],
[ "RegExp.exec", JS_E_REGEXP_EXPECTED, function(ctx) { RegExp.prototype.exec.call(ctx, "foobar"); } ], [ "RegExp.exec", JS_E_REGEXP_EXPECTED, function(ctx) { RegExp.prototype.exec.call(ctx, "foobar"); } ],
[ "Set.add", JS_E_OBJECT_EXPECTED, function(ctx) { Set.prototype.add.call(ctx, 5); } ],
[ "String.search", JS_E_OBJECT_EXPECTED, function(ctx) { String.prototype.search.call(ctx, /foobar/g); } ], [ "String.search", JS_E_OBJECT_EXPECTED, function(ctx) { String.prototype.search.call(ctx, /foobar/g); } ],
[ "String.trim", JS_E_OBJECT_EXPECTED, function(ctx) { String.prototype.trim.call(ctx); } ], [ "String.trim", JS_E_OBJECT_EXPECTED, function(ctx) { String.prototype.trim.call(ctx); } ],
[ "VBArray.dimensions", JS_E_VBARRAY_EXPECTED, function(ctx) { VBArray.prototype.dimensions.call(ctx); } ] [ "VBArray.dimensions", JS_E_VBARRAY_EXPECTED, function(ctx) { VBArray.prototype.dimensions.call(ctx); } ]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment