diff R/rdyncall/src/rcallback.c @ 0:0cfcc391201f

initial from svn dyncall-1745
author Daniel Adler
date Thu, 19 Mar 2015 22:26:28 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/R/rdyncall/src/rcallback.c	Thu Mar 19 22:26:28 2015 +0100
@@ -0,0 +1,222 @@
+/** ===========================================================================
+ ** R-Package: rdyncall
+ ** File: src/rcallback.c
+ ** Description: dyncall callback R backend
+ **/
+
+#include "Rinternals.h"
+#include "Rdefines.h"
+#include "dyncall_callback.h"
+
+typedef struct
+{
+  int         disabled;
+  SEXP        fun;
+  SEXP        rho;
+  int         nargs;
+  const char* signature; /* argument signature without call mode prefix */
+} R_Callback;
+
+char dcCallbackHandler_R( DCCallback* pcb, DCArgs* args, DCValue* result, void* userdata )
+{
+	R_Callback* rdata;
+	const char* ptr;
+	int i,n;
+	SEXP s, x, ans, item;
+	char ch;
+
+	rdata = (R_Callback*) userdata;
+
+	if (rdata->disabled) return DC_SIGCHAR_VOID;
+
+	ptr = rdata->signature;
+
+	// allocate an nargs + 1 'call' language object
+	//   first argument is function
+	//   rest is arguments from callback
+	n = 1 + rdata->nargs;
+
+	PROTECT( s = allocList(n) );
+	SET_TYPEOF(s, LANGSXP);
+	SETCAR( s, rdata->fun ); x = CDR(s);
+
+	// fill up call object
+
+	i = 1;
+	for( ;; ++i) {
+		ch = *ptr++;
+		if (ch == ')') break;
+		if (i >= n) {
+			warning("invalid signature.");
+			rdata->disabled = 1;
+			UNPROTECT(1);
+			return DC_SIGCHAR_VOID;
+		}
+		switch(ch) {
+		case DC_SIGCHAR_BOOL:      item = ScalarLogical( ( dcbArgBool(args) == DC_FALSE ) ? FALSE : TRUE ); break;
+		case DC_SIGCHAR_CHAR:      item = ScalarInteger( (int) dcbArgChar(args) ); break;
+		case DC_SIGCHAR_UCHAR:     item = ScalarInteger( (int) dcbArgUChar(args) ); break;
+		case DC_SIGCHAR_SHORT:     item = ScalarInteger( (int) dcbArgShort(args) ); break;
+		case DC_SIGCHAR_USHORT:    item = ScalarInteger( (int) dcbArgUShort(args) ); break;
+		case DC_SIGCHAR_INT:       item = ScalarInteger( (int) dcbArgInt(args) ); break;
+		case DC_SIGCHAR_UINT:      item = ScalarReal( (double) dcbArgUInt(args) ); break;
+		case DC_SIGCHAR_LONG:      item = ScalarReal( (double) dcbArgLong(args) ); break;
+		case DC_SIGCHAR_ULONG:     item = ScalarReal( (double) dcbArgULong(args) ); break;
+		case DC_SIGCHAR_LONGLONG:  item = ScalarReal( (double) dcbArgLongLong(args) ); break;
+		case DC_SIGCHAR_ULONGLONG: item = ScalarReal( (double) dcbArgULongLong(args) ); break;
+		case DC_SIGCHAR_FLOAT:     item = ScalarReal( (double) dcbArgFloat(args) ); break;
+		case DC_SIGCHAR_DOUBLE:    item = ScalarReal( dcbArgDouble(args) ); break;
+		case DC_SIGCHAR_POINTER:   item = R_MakeExternalPtr( dcbArgPointer(args), R_NilValue, R_NilValue ); break;
+		case DC_SIGCHAR_STRING:    item = mkString( dcbArgPointer(args) ); break;
+		default:
+		case '\0':
+			warning("invalid signature");
+			rdata->disabled = 1;
+			UNPROTECT(1);
+			return DC_SIGCHAR_VOID;
+		}
+		SETCAR( x, item);
+		x = CDR(x);
+	}
+
+	/* evaluate expression */
+
+	int error = 0;
+
+	PROTECT( ans = R_tryEval( s, rdata->rho, &error ) );
+
+	if (error)
+	{
+		warning("an error occurred during callback invocation in R. Callback disabled.");
+		rdata->disabled = 1;
+		UNPROTECT(2);
+		return DC_SIGCHAR_VOID;
+	}
+
+	/* propagate return value */
+
+	ch = *ptr;	/* scan return value type character */
+
+	/* handle NULL and len(x) == 0 expressions special */
+	if ( (ans == R_NilValue) || (LENGTH(ans) == 0) )
+	{
+		/* handle NULL */
+		result->L = 0;
+	}
+	else
+	{
+		switch(ch)
+		{
+		case DC_SIGCHAR_VOID:
+			break;
+		case DC_SIGCHAR_BOOL:
+			switch( TYPEOF(ans) )
+			{
+			case INTSXP: result->B = (INTEGER(ans)[0] == 0 ) ? DC_FALSE : DC_TRUE; break;
+			case LGLSXP: result->B = (LOGICAL(ans)[0] == FALSE ) ? DC_FALSE : DC_TRUE; break;
+			default:     result->B = DC_FALSE; break;
+			}
+			break;
+		case DC_SIGCHAR_CHAR:
+		case DC_SIGCHAR_UCHAR:
+		case DC_SIGCHAR_SHORT:
+		case DC_SIGCHAR_USHORT:
+		case DC_SIGCHAR_INT:
+		case DC_SIGCHAR_UINT:
+		case DC_SIGCHAR_LONG:
+		case DC_SIGCHAR_ULONG:
+			switch( TYPEOF(ans) )
+			{
+			case INTSXP:  result->i = INTEGER(ans)[0]; break;
+			case REALSXP: result->i = (int) REAL(ans)[0]; break;
+			default:      result->i = 0; break;
+			}
+			break;
+		case DC_SIGCHAR_ULONGLONG:
+		case DC_SIGCHAR_LONGLONG:
+			switch( TYPEOF(ans) )
+			{
+			case INTSXP:  result->L = (long long) INTEGER(ans)[0]; break;
+			case REALSXP: result->L = (long long) REAL(ans)[0]; break;
+			default:      result->L = 0; break;
+			}
+			break;
+		case DC_SIGCHAR_FLOAT:
+			switch( TYPEOF(ans) )
+			{
+			case INTSXP:  result->f = (float) INTEGER(ans)[0]; break;
+			case REALSXP: result->f = (float) REAL(ans)[0]; break;
+			default:      result->f = 0.0f; break;
+			}
+			break;
+		case DC_SIGCHAR_DOUBLE:
+			switch( TYPEOF(ans) )
+			{
+			case INTSXP:  result->d = (double) INTEGER(ans)[0]; break;
+			case REALSXP: result->d = REAL(ans)[0]; break;
+			default:      result->d = 0.0; break;
+			}
+			break;
+		case DC_SIGCHAR_POINTER:
+			switch( TYPEOF(ans) )
+			{
+			case EXTPTRSXP: result->p = R_ExternalPtrAddr(ans); break;
+			case INTSXP   : result->p = (DCpointer) (ptrdiff_t) (unsigned long long int) INTEGER(ans)[0]; break;
+			case REALSXP  : result->p = (DCpointer) (ptrdiff_t) (unsigned long long int) REAL(ans)[0]; break;
+			default:        result->p = NULL; break;
+			}
+			break;
+		case DC_SIGCHAR_STRING:
+			warning("not implemented");
+			rdata->disabled = 1;
+			break;
+		}
+	}
+	UNPROTECT(2);
+	return ch;
+}
+
+void R_callback_finalizer(SEXP x);
+
+SEXP r_new_callback(SEXP sig_x, SEXP fun_x, SEXP rho_x)
+{
+  const char* signature;
+  R_Callback* rdata;
+  const char* ptr;
+  char ch;
+  signature  = CHAR( STRING_ELT( sig_x, 0 ) );
+  rdata = Calloc(1, R_Callback);
+  rdata->disabled = 0;
+  rdata->fun = fun_x;
+  rdata->rho = rho_x;
+  R_PreserveObject(rdata->fun);
+  R_PreserveObject(rdata->rho);
+  ptr = signature;
+  // skip call mode signature
+  if ( (ch=*ptr) == '_') {
+    ptr += 2;
+    ch=*ptr;
+  }
+  rdata->signature = ptr++;
+  int nargs = 0;
+  while( ch != ')') {
+    nargs ++;
+    ch = *ptr++;
+  }
+  rdata->nargs = nargs;
+  DCCallback* cb = dcbNewCallback( signature, dcCallbackHandler_R, rdata);
+  SEXP ans = R_MakeExternalPtr( cb, R_NilValue, R_NilValue );
+  R_RegisterCFinalizerEx(ans, R_callback_finalizer, TRUE);
+  return ans;
+}
+
+void R_callback_finalizer(SEXP x)
+{
+  DCCallback* cb = R_ExternalPtrAddr(x);
+  R_Callback* rdata = dcbGetUserData(cb);
+  R_ReleaseObject(rdata->fun);
+  R_ReleaseObject(rdata->rho);
+  Free(rdata);
+  dcbFreeCallback(cb);
+}
+