]> git.mxchange.org Git - simgear.git/commitdiff
Add optional user_data to Nasal C functions.
authorThomas Geymayer <tomgey@gmail.com>
Fri, 1 Mar 2013 11:22:51 +0000 (12:22 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Fri, 1 Mar 2013 11:22:51 +0000 (12:22 +0100)
A user_data pointer and another pointer to an optional
deleter function is stored in unused parts of the naPtr
union. The previous behavior of extension functions does
not change. Only one additional boolean comparison is
required upon each function call to check whether user
data is available.

simgear/nasal/code.c
simgear/nasal/data.h
simgear/nasal/gc.c
simgear/nasal/misc.c
simgear/nasal/nasal.h

index 511f490f51b2c3b776b5dbb7f9bf9752f89ed410..5601b074d663e9e6eac444f6bfb6b76e946bc952 100644 (file)
@@ -313,7 +313,10 @@ static struct Frame* setupFuncall(naContext ctx, int nargs, int mcall, int named
     ctx->opFrame = opf;
 
     if(IS_CCODE(code)) {
-        naRef result = (*PTR(code).ccode->fptr)(ctx, obj, nargs, args);
+        struct naCCode *ccode = PTR(code).ccode;
+        naRef result = ccode->fptru
+                     ? (*ccode->fptru)(ctx, obj, nargs, args, ccode->user_data)
+                     : (*ccode->fptr)(ctx, obj, nargs, args);
         if(named) ERR(ctx, "native functions have no named arguments");
         ctx->opTop = ctx->opFrame;
         PUSH(result);
index deb4fbdc194abd2618edb510d3cbbb8b0aef750c..a2c023ef2fd324e9ca366a3c61ef239d55a38491 100644 (file)
@@ -160,7 +160,15 @@ struct naFunc {
 
 struct naCCode {
     GC_HEADER;
-    naCFunction fptr;
+    union {
+        naCFunction fptr; //<! pointer to simple callback function. Invalid if
+                          //   fptru is not NULL.
+        struct {
+            void* user_data;
+            void(*destroy)(void*);
+            naCFunctionU fptru;
+        };
+    };
 };
 
 struct naGhost {
index e9d9b7b8ba60587f9618eca6e25fab55a3a8a5f5..9773c795237c6e4ae5bc0a565490bcbf878a9444 100644 (file)
@@ -128,6 +128,12 @@ static void naCode_gcclean(struct naCode* o)
     naFree(o->constants);  o->constants = 0;
 }
 
+static void naCCode_gcclean(struct naCCode* c)
+{
+    if(c->fptru && c->user_data && c->destroy) c->destroy(c->user_data);
+    c->user_data = 0;
+}
+
 static void naGhost_gcclean(struct naGhost* g)
 {
     if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr);
@@ -142,6 +148,7 @@ static void freeelem(struct naPool* p, struct naObj* o)
     case T_VEC:   naVec_gcclean  ((struct naVec*)  o); break;
     case T_HASH:  naiGCHashClean ((struct naHash*) o); break;
     case T_CODE:  naCode_gcclean ((struct naCode*) o); break;
+    case T_CCODE: naCCode_gcclean((struct naCCode*)o); break;
     case T_GHOST: naGhost_gcclean((struct naGhost*)o); break;
     }
     p->free[p->nfree++] = o;  // ...and add it to the free list
index dae0bfe48feae8fe8ea1379677f87a591b9d4da3..a249fce70332fb186e991fddb46a9d863acec7db 100644 (file)
@@ -107,6 +107,24 @@ naRef naNewCCode(struct Context* c, naCFunction fptr)
 {
     naRef r = naNew(c, T_CCODE);
     PTR(r).ccode->fptr = fptr;
+    PTR(r).ccode->fptru = 0;
+    return r;
+}
+
+naRef naNewCCodeU(struct Context* c, naCFunctionU fptr, void* user_data)
+{
+    return naNewCCodeUD(c, fptr, user_data, 0);
+}
+
+naRef naNewCCodeUD( struct Context* c,
+                    naCFunctionU fptr,
+                    void* user_data,
+                    void (*destroy)(void*) )
+{
+    naRef r = naNew(c, T_CCODE);
+    PTR(r).ccode->fptru = fptr;
+    PTR(r).ccode->user_data = user_data;
+    PTR(r).ccode->destroy = destroy;
     return r;
 }
 
index 7fc54203a7e8c550c1014b436ad0d6d3b83b49a5..d3cb916736f5225d8f467598f5df6e7151b1c6c0 100644 (file)
@@ -16,10 +16,14 @@ extern "C" {
 #endif
 
 typedef struct Context* naContext;
-    
+
 // The function signature for an extension function:
 typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
 
+// The function signature for an extension function with userdata passed back:
+typedef naRef (*naCFunctionU)
+              (naContext ctx, naRef me, int argc, naRef* args, void* user_data);
+
 // All Nasal code runs under the watch of a naContext:
 naContext naNewContext();
 void naFreeContext(naContext c);
@@ -146,7 +150,19 @@ naRef naNewString(naContext c);
 naRef naNewVector(naContext c);
 naRef naNewHash(naContext c);
 naRef naNewFunc(naContext c, naRef code);
+
+/**
+ * Register extension function
+ *
+ * @param fptr      Pointer to C-function
+ * @param user_data Optional user data passed back on calling the function
+ * @param destroy   Optional callback called if function gets freed by garbage
+ *                  collector to free user data if required.
+ */
 naRef naNewCCode(naContext c, naCFunction fptr);
+naRef naNewCCodeU(naContext c, naCFunctionU fptr, void* user_data);
+naRef naNewCCodeUD(naContext c, naCFunctionU fptr, void* user_data,
+                                                   void (*destroy)(void*));
 
 // Some useful conversion/comparison routines
 int naEqual(naRef a, naRef b) GCC_PURE;