Jacek Caban : jscript: Added Array.sort implementation.

Alexandre Julliard julliard at winehq.org
Mon Sep 22 07:04:06 CDT 2008


Module: wine
Branch: master
Commit: f1f2e8e6c575922d28216fd9a7be42458a770c60
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f1f2e8e6c575922d28216fd9a7be42458a770c60

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Sun Sep 21 15:38:28 2008 +0200

jscript: Added Array.sort implementation.

---

 dlls/jscript/array.c      |  210 ++++++++++++++++++++++++++++++++++++++++++++-
 dlls/jscript/engine.c     |   10 --
 dlls/jscript/jscript.h    |   10 ++
 dlls/jscript/tests/api.js |   20 +++++
 4 files changed, 237 insertions(+), 13 deletions(-)

diff --git a/dlls/jscript/array.c b/dlls/jscript/array.c
index 9d7c8d8..11ae558 100644
--- a/dlls/jscript/array.c
+++ b/dlls/jscript/array.c
@@ -265,11 +265,215 @@ static HRESULT Array_slice(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS
     return E_NOTIMPL;
 }
 
+static HRESULT sort_cmp(script_ctx_t *ctx, DispatchEx *cmp_func, VARIANT *v1, VARIANT *v2, jsexcept_t *ei,
+        IServiceProvider *caller, INT *cmp)
+{
+    HRESULT hres;
+
+    if(cmp_func) {
+        VARIANTARG args[2];
+        DISPPARAMS dp = {args, NULL, 2, 0};
+        VARIANT tmp;
+        VARIANT res;
+
+        args[0] = *v2;
+        args[1] = *v1;
+
+        hres = jsdisp_call_value(cmp_func, ctx->lcid, DISPATCH_METHOD, &dp, &res, ei, caller);
+        if(FAILED(hres))
+            return hres;
+
+        hres = to_number(ctx, &res, ei, &tmp);
+        VariantClear(&res);
+        if(FAILED(hres))
+            return hres;
+
+        if(V_VT(&tmp) == VT_I4)
+            *cmp = V_I4(&tmp);
+        else
+            *cmp = V_R8(&tmp) > 0.0 ? 1 : -1;
+    }else if(is_num_vt(V_VT(v1))) {
+        if(is_num_vt(V_VT(v2))) {
+            DOUBLE d = num_val(v1)-num_val(v2);
+            if(d > 0.0)
+                *cmp = 1;
+            else if(d < -0.0)
+                *cmp = -1;
+            else
+                *cmp = 0;
+        }else {
+            *cmp = -1;
+        }
+    }else if(is_num_vt(V_VT(v2))) {
+        *cmp = 1;
+    }else if(V_VT(v1) == VT_BSTR) {
+        if(V_VT(v2) == VT_BSTR)
+            *cmp = strcmpW(V_BSTR(v1), V_BSTR(v2));
+        else
+            *cmp = -1;
+    }else if(V_VT(v2) == VT_BSTR) {
+        *cmp = 1;
+    }else {
+        *cmp = 0;
+    }
+
+    return S_OK;
+}
+
+/* ECMA-262 3rd Edition    15.4.4.11 */
 static HRESULT Array_sort(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
-        VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
+        VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    DispatchEx *cmp_func = NULL;
+    VARIANT *vtab, **sorttab = NULL;
+    DWORD length;
+    DWORD i;
+    HRESULT hres = S_OK;
+
+    TRACE("\n");
+
+    if(is_class(dispex, JSCLASS_ARRAY)) {
+        length = ((ArrayInstance*)dispex)->length;
+    }else {
+        FIXME("unsupported this not array\n");
+        return E_NOTIMPL;
+    }
+
+    if(arg_cnt(dp) > 1) {
+        WARN("invalid arg_cnt %d\n", arg_cnt(dp));
+        return E_FAIL;
+    }
+
+    if(arg_cnt(dp) == 1) {
+        VARIANT *arg = get_arg(dp, 0);
+
+        if(V_VT(arg) != VT_DISPATCH) {
+            WARN("arg is not dispatch\n");
+            return E_FAIL;
+        }
+
+
+        cmp_func = iface_to_jsdisp((IUnknown*)V_DISPATCH(arg));
+        if(!is_class(cmp_func, JSCLASS_FUNCTION)) {
+            WARN("cmp_func is not a function\n");
+            jsdisp_release(cmp_func);
+            return E_FAIL;
+        }
+    }
+
+    if(!length) {
+        if(cmp_func)
+            jsdisp_release(cmp_func);
+        if(retv) {
+            V_VT(retv) = VT_DISPATCH;
+            V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(dispex);
+	    IDispatchEx_AddRef(_IDispatchEx_(dispex));
+        }
+        return S_OK;
+    }
+
+    vtab = heap_alloc_zero(length * sizeof(VARIANT));
+    if(vtab) {
+        for(i=0; i<length; i++) {
+            hres = jsdisp_propget_idx(dispex, i, lcid, vtab+i, ei, caller);
+            if(FAILED(hres) && hres != DISP_E_UNKNOWNNAME) {
+                WARN("Could not get elem %d: %08x\n", i, hres);
+                break;
+            }
+        }
+    }else {
+        hres = E_OUTOFMEMORY;
+    }
+
+    if(SUCCEEDED(hres)) {
+        sorttab = heap_alloc(length*2*sizeof(VARIANT*));
+        if(!sorttab)
+            hres = E_OUTOFMEMORY;
+    }
+
+    /* merge-sort */
+    if(SUCCEEDED(hres)) {
+        VARIANT *tmpv, **tmpbuf;
+        INT cmp;
+
+        tmpbuf = sorttab + length;
+        for(i=0; i < length; i++)
+            sorttab[i] = vtab+i;
+
+        for(i=0; i < length/2; i++) {
+            hres = sort_cmp(dispex->ctx, cmp_func, sorttab[2*i+1], sorttab[2*i], ei, caller, &cmp);
+            if(FAILED(hres))
+                break;
+
+            if(cmp < 0) {
+                tmpv = sorttab[2*i];
+                sorttab[2*i] = sorttab[2*i+1];
+                sorttab[2*i+1] = tmpv;
+            }
+        }
+
+        if(SUCCEEDED(hres)) {
+            DWORD k, a, b, bend;
+
+            for(k=2; k < length; k *= 2) {
+                for(i=0; i+k < length; i += 2*k) {
+                    a = b = 0;
+                    if(i+2*k <= length)
+                        bend = k;
+                    else
+                        bend = length - (i+k);
+
+                    memcpy(tmpbuf, sorttab+i, k*sizeof(VARIANT*));
+
+                    while(a < k && b < bend) {
+                        hres = sort_cmp(dispex->ctx, cmp_func, tmpbuf[a], sorttab[i+k+b], ei, caller, &cmp);
+                        if(FAILED(hres))
+                            break;
+
+                        if(cmp < 0) {
+                            sorttab[i+a+b] = tmpbuf[a];
+                            a++;
+                        }else {
+                            sorttab[i+a+b] = sorttab[i+k+b];
+                            b++;
+                        }
+                    }
+
+                    if(FAILED(hres))
+                        break;
+
+                    if(a < k)
+                        memcpy(sorttab+i+a+b, tmpbuf+a, (k-a)*sizeof(VARIANT*));
+                }
+
+                if(FAILED(hres))
+                    break;
+            }
+        }
+
+        for(i=0; SUCCEEDED(hres) && i < length; i++)
+            hres = jsdisp_propput_idx(dispex, i, lcid, sorttab[i], ei, caller);
+    }
+
+    if(vtab) {
+        for(i=0; i < length; i++)
+            VariantClear(vtab+i);
+        heap_free(vtab);
+    }
+    heap_free(sorttab);
+    if(cmp_func)
+        jsdisp_release(cmp_func);
+
+    if(FAILED(hres))
+        return hres;
+
+    if(retv) {
+        V_VT(retv) = VT_DISPATCH;
+        V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(dispex);
+        IDispatch_AddRef(_IDispatchEx_(dispex));
+    }
+
+    return S_OK;
 }
 
 static HRESULT Array_splice(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
diff --git a/dlls/jscript/engine.c b/dlls/jscript/engine.c
index f0f5062..86ddbdd 100644
--- a/dlls/jscript/engine.c
+++ b/dlls/jscript/engine.c
@@ -278,16 +278,6 @@ static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, BOOL *ret)
     return S_OK;
 }
 
-static inline BOOL is_num_vt(enum VARENUM vt)
-{
-    return vt == VT_I4 || vt == VT_R8;
-}
-
-static inline DOUBLE num_val(const VARIANT *v)
-{
-    return V_VT(v) == VT_I4 ? V_I4(v) : V_R8(v);
-}
-
 /* ECMA-262 3rd Edition    11.9.6 */
 HRESULT equal2_values(VARIANT *lval, VARIANT *rval, BOOL *ret)
 {
diff --git a/dlls/jscript/jscript.h b/dlls/jscript/jscript.h
index 1857459..ed248c1 100644
--- a/dlls/jscript/jscript.h
+++ b/dlls/jscript/jscript.h
@@ -214,6 +214,16 @@ static inline BOOL is_class(DispatchEx *jsdisp, jsclass_t class)
     return jsdisp->builtin_info->class == class;
 }
 
+static inline BOOL is_num_vt(enum VARENUM vt)
+{
+    return vt == VT_I4 || vt == VT_R8;
+}
+
+static inline DOUBLE num_val(const VARIANT *v)
+{
+    return V_VT(v) == VT_I4 ? V_I4(v) : V_R8(v);
+}
+
 static inline void num_set_val(VARIANT *v, DOUBLE d)
 {
     if(d == (DOUBLE)(INT)d) {
diff --git a/dlls/jscript/tests/api.js b/dlls/jscript/tests/api.js
index ecc6da4..9fa392e 100644
--- a/dlls/jscript/tests/api.js
+++ b/dlls/jscript/tests/api.js
@@ -84,6 +84,26 @@ ok(tmp === "1,2,,false,,,a", "arr.toString() = " + tmp);
 tmp = arr.toString("test");
 ok(tmp === "1,2,,false,,,a", "arr.toString() = " + tmp);
 
+arr = [5,true,2,-1,3,false,"2.5"];
+tmp = arr.sort(function(x,y) { return y-x; });
+ok(tmp === arr, "tmp !== arr");
+tmp = [5,3,"2.5",2,true,false,-1];
+for(var i=0; i < arr.length; i++)
+    ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]);
+
+arr = [5,false,2,0,"abc",3,"a",-1];
+tmp = arr.sort();
+ok(tmp === arr, "tmp !== arr");
+tmp = [-1,0,2,3,5,"a","abc",false];
+for(var i=0; i < arr.length; i++)
+    ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]);
+
+arr = ["a", "b", "ab"];
+tmp = ["a", "ab", "b"];
+ok(arr.sort() === arr, "arr.sort() !== arr");
+for(var i=0; i < arr.length; i++)
+    ok(arr[i] === tmp[i], "arr[" + i + "] = " + arr[i] + " expected " + tmp[i]);
+
 var num = new Number(2);
 ok(num.toString() === "2", "num(2).toString !== 2");
 var num = new Number();




More information about the wine-cvs mailing list