Add optional user_data to Nasal C functions.
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.
This commit is contained in:
parent
081eba903f
commit
5e45bdeeda
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user