]> git.mxchange.org Git - simgear.git/commitdiff
sync with Nasal CVS (added a sort() builtin)
authorandy <andy>
Fri, 6 Apr 2007 14:52:06 +0000 (14:52 +0000)
committerandy <andy>
Fri, 6 Apr 2007 14:52:06 +0000 (14:52 +0000)
simgear/nasal/lib.c

index 0d4253f99f0e8bcab27828a401619f6067871b49..8763d0ddb93d5c41182210cb1ae3e0785a89754a 100644 (file)
@@ -479,6 +479,60 @@ static naRef f_bind(naContext c, naRef me, int argc, naRef* args)
     return func;
 }
 
+/* We use the "SortRec" gadget for two reasons: first, because ANSI
+ * qsort() doesn't give us a mechanism for passing a "context" pointer
+ * to the comparison routine we have to store one in every sorted
+ * record.  Second, using an index into the original vector here
+ * allows us to make the sort stable in the event of a zero returned
+ * from the Nasal comparison function. */
+struct SortData { naContext ctx, subc; struct SortRec* recs;
+                  naRef* elems; int n; naRef fn; };
+struct SortRec { struct SortData* sd; int i; };
+
+static int sortcmp(struct SortRec* a, struct SortRec* b)
+{
+    struct SortData* sd = a->sd;
+    naRef args[2], d;
+    args[0] = sd->elems[a->i];
+    args[1] = sd->elems[b->i];
+    d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil());
+    if(naGetError(sd->subc)) {
+        naFree(sd->recs);
+        naRethrowError(sd->subc);
+    } else if(!naIsNum(d = naNumValue(d))) {
+        naFree(sd->recs);
+        naRuntimeError(sd->ctx, "sort() comparison returned non-number");
+    }
+    return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i));
+}
+
+static naRef f_sort(naContext c, naRef me, int argc, naRef* args)
+{
+    int i;
+    struct SortData sd;
+    naRef out;
+    if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1]))
+        naRuntimeError(c, "bad/missing argument to sort()");
+    sd.subc = naSubContext(c);
+    sd.elems = PTR(args[0]).vec->rec->array;
+    sd.n = PTR(args[0]).vec->rec->size;
+    sd.fn = args[1];
+    sd.recs = naAlloc(sizeof(struct SortRec) * sd.n);
+    for(i=0; i<sd.n; i++) {
+        sd.recs[i].sd = &sd;
+        sd.recs[i].i = i;
+    }
+    qsort(sd.recs, sd.n, sizeof(sd.recs[0]),
+          (int(*)(const void*,const void*))sortcmp);
+    out = naNewVector(c);
+    naVec_setsize(out, sd.n);
+    for(i=0; i<sd.n; i++)
+        PTR(out).vec->rec->array[i] = sd.elems[sd.recs[i].i];
+    naFree(sd.recs);
+    naFreeContext(sd.subc);
+    return out;
+}
+
 static naCFuncItem funcs[] = {
     { "size", f_size },
     { "keys", f_keys }, 
@@ -506,6 +560,7 @@ static naCFuncItem funcs[] = {
     { "split", f_split },
     { "rand", f_rand },
     { "bind", f_bind },
+    { "sort", f_sort },
     { 0 }
 };