diff R/rdyncall/src/rpack.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/rpack.c	Thu Mar 19 22:26:28 2015 +0100
@@ -0,0 +1,336 @@
+/** ===========================================================================
+ ** R-Package: rdyncall
+ ** File: src/rpack.c
+ ** Description: (un-)packing of C structure data
+ ** TODO
+ ** - support for bitfields
+ **/
+
+// #define USE_RINTERNALS
+#include <Rinternals.h>
+#include <string.h>
+#include <stddef.h>
+#include "rdyncall_signature.h"
+/** ---------------------------------------------------------------------------
+ ** C-Function: r_dataptr
+ ** Description: retrieve the 'data' pointer on an R expression.
+ ** R-Calling Convention: .Call
+ **
+ **/
+
+static char* r_dataptr(SEXP x, SEXP off, size_t element_size)
+{
+  if ( LENGTH(off) == 0 ) error("missing offset");
+  char* p = NULL;
+  ptrdiff_t o = INTEGER(off)[0], s = 0;
+  
+  switch(TYPEOF(x))
+  {
+    case CHARSXP:   p = (char*) CHAR(x);    s = LENGTH(x)*sizeof(char); break;
+    case LGLSXP:    p = (char*) LOGICAL(x); s = LENGTH(x)*sizeof(Rboolean); break;
+    case INTSXP:    p = (char*) INTEGER(x); s = LENGTH(x)*sizeof(int); break;
+    case REALSXP:   p = (char*) REAL(x);    s = LENGTH(x)*sizeof(double); break;
+    case CPLXSXP:   p = (char*) COMPLEX(x); s = LENGTH(x)*sizeof(Rcomplex); break; 
+    case STRSXP:    p = (char*) CHAR( STRING_ELT(x,0) ); s = strlen(p)*sizeof(char); break;
+    case RAWSXP:    p = (char*) RAW(x); s = LENGTH(x)*sizeof(char); break;
+    case EXTPTRSXP: return (char*) R_ExternalPtrAddr(x) + o; break;
+    default: error("invalid object type"); break;
+  }
+  if (p == NULL) error("NULL address pointer");
+  if (o < 0 || o+element_size > s) error("offset %d is out-of-bounds of the R object (max size %d)", o, s);
+  return p + o; 
+}
+
+
+
+/** ---------------------------------------------------------------------------
+ ** C-Function: r_pack
+ ** Description: pack R data type into a C data type
+ ** R-Calling Convention: .Call
+ **
+ **/
+SEXP r_pack(SEXP ptr_x, SEXP offset, SEXP sig_x, SEXP value_x)
+{
+  int type_of = TYPEOF(value_x);
+  const char* sig = CHAR(STRING_ELT(sig_x,0) );
+  switch(sig[0])
+  {
+    case DC_SIGCHAR_BOOL:
+    {
+      int* Bp = (int*) r_dataptr(ptr_x, offset, sizeof(Rboolean));
+      switch(type_of)
+      {
+        case LGLSXP:  *Bp = (int) LOGICAL(value_x)[0]; break;
+        case INTSXP:  *Bp = (int) ( INTEGER(value_x)[0] == 0) ? 0 : 1; break;
+        case REALSXP: *Bp = (int) ( REAL(value_x)[0] == 0.0) ? 0 : 1; break;
+        case RAWSXP:  *Bp = (int) ( RAW(value_x)[0] == 0) ? 0 : 1; break;
+	default: error("value mismatch with 'B' pack type");
+      }
+    }
+    break;
+    case DC_SIGCHAR_CHAR:
+    {
+      char* cp = (char*) r_dataptr(ptr_x, offset, sizeof(char));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *cp = (char) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *cp = (char) INTEGER(value_x)[0]; break;
+	  case REALSXP: *cp = (char) REAL(value_x)[0];    break;
+	  case RAWSXP:  *cp = (char) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'c' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_UCHAR:
+	{
+	  unsigned char* cp = (unsigned char*) r_dataptr(ptr_x,offset,sizeof(unsigned char));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *cp = (unsigned char) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *cp = (unsigned char) INTEGER(value_x)[0]; break;
+	  case REALSXP: *cp = (unsigned char) REAL(value_x)[0];    break;
+	  case RAWSXP:  *cp = (unsigned char) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'C' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_SHORT:
+	{
+	  short* sp = (short*) r_dataptr(ptr_x,offset,sizeof(short));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *sp = (short) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *sp = (short) INTEGER(value_x)[0]; break;
+	  case REALSXP: *sp = (short) REAL(value_x)[0];    break;
+	  case RAWSXP:  *sp = (short) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 's' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_USHORT:
+	{
+	  unsigned short* sp = (unsigned short*) r_dataptr(ptr_x,offset,sizeof(unsigned short));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *sp = (unsigned short) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *sp = (unsigned short) INTEGER(value_x)[0]; break;
+	  case REALSXP: *sp = (unsigned short) REAL(value_x)[0];    break;
+	  case RAWSXP:  *sp = (unsigned short) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'S' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_INT:
+	{
+	  int* ip = (int*) r_dataptr(ptr_x,offset,sizeof(int));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *ip = (int) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *ip = (int) INTEGER(value_x)[0]; break;
+	  case REALSXP: *ip = (int) REAL(value_x)[0];    break;
+	  case RAWSXP:  *ip = (int) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'i' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_UINT:
+	{
+	  unsigned int* ip = (unsigned int*) r_dataptr(ptr_x,offset,sizeof(unsigned int));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *ip = (unsigned int) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *ip = (unsigned int) INTEGER(value_x)[0]; break;
+	  case REALSXP: *ip = (unsigned int) REAL(value_x)[0];    break;
+	  case RAWSXP:  *ip = (unsigned int) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'I' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_LONG:
+	{
+	  long* ip = (long*) r_dataptr(ptr_x,offset,sizeof(long));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *ip = (long) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *ip = (long) INTEGER(value_x)[0]; break;
+	  case REALSXP: *ip = (long) REAL(value_x)[0];    break;
+	  case RAWSXP:  *ip = (long) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'j' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_ULONG:
+	{
+	  unsigned long* ip = (unsigned long*) r_dataptr(ptr_x,offset,sizeof(unsigned long));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *ip = (unsigned long) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *ip = (unsigned long) INTEGER(value_x)[0]; break;
+	  case REALSXP: *ip = (unsigned long) REAL(value_x)[0];    break;
+	  case RAWSXP:  *ip = (unsigned long) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'J' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_LONGLONG:
+	{
+	  long long* Lp = (long long*) r_dataptr(ptr_x,offset,sizeof(long long));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *Lp = (long long) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *Lp = (long long) INTEGER(value_x)[0]; break;
+	  case REALSXP: *Lp = (long long) REAL(value_x)[0];    break;
+	  case RAWSXP:  *Lp = (long long) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'l' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_ULONGLONG:
+	{
+	  unsigned long long* Lp = (unsigned long long*) r_dataptr(ptr_x,offset,sizeof(unsigned long long));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *Lp = (unsigned long long) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *Lp = (unsigned long long) INTEGER(value_x)[0]; break;
+	  case REALSXP: *Lp = (unsigned long long) REAL(value_x)[0];    break;
+	  case RAWSXP:  *Lp = (unsigned long long) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'L' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_FLOAT:
+	{
+	  float* fp = (float*) r_dataptr(ptr_x,offset,sizeof(float));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *fp = (float) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *fp = (float) INTEGER(value_x)[0]; break;
+	  case REALSXP: *fp = (float) REAL(value_x)[0];    break;
+	  case RAWSXP:  *fp = (float) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'f' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_DOUBLE:
+	{
+	  double* dp = (double*) r_dataptr(ptr_x,offset,sizeof(double));
+	  switch(type_of)
+	  {
+	  case LGLSXP:  *dp = (double) LOGICAL(value_x)[0]; break;
+	  case INTSXP:  *dp = (double) INTEGER(value_x)[0]; break;
+	  case REALSXP: *dp = (double) REAL(value_x)[0];    break;
+	  case RAWSXP:  *dp = (double) RAW(value_x)[0];     break;
+	  default: error("value mismatch with 'd' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_POINTER:
+	case '*':
+	{
+	  void** pp = (void**) r_dataptr(ptr_x,offset,sizeof(void*));
+	  switch(type_of)
+	  {
+	  case NILSXP:   *pp = (void*) 0; break;
+	  case CHARSXP:  *pp = (void*) CHAR(value_x); break;
+	  case LGLSXP:   *pp = (void*) LOGICAL(value_x); break;
+	  case INTSXP:   *pp = (void*) INTEGER(value_x); break;
+	  case REALSXP:  *pp = (void*) REAL(value_x); break;
+	  case CPLXSXP:  *pp = (void*) COMPLEX(value_x); break;
+	  case STRSXP:   *pp = (void*) CHAR( STRING_ELT(value_x,0) ); break;
+	  case EXTPTRSXP:*pp = (void*) R_ExternalPtrAddr(value_x); break;
+	  case RAWSXP:   *pp = (void*) RAW(value_x); break;
+	  default: error("value type mismatch with 'p' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_STRING:
+	{
+	  char** Sp = (char**) r_dataptr(ptr_x,offset,sizeof(char*));
+	  switch(type_of)
+	  {
+	  case NILSXP:   *Sp = (char*) NULL; break;
+	  case CHARSXP:  *Sp = (char*) CHAR(value_x); break;
+	  case STRSXP:   *Sp = (char*) CHAR( STRING_ELT(value_x,0) ); break;
+	  case EXTPTRSXP:*Sp = (char*) R_ExternalPtrAddr(value_x); break;
+	  default: error("value type mismatch with 'Z' pack type");
+	  }
+	}
+	break;
+	case DC_SIGCHAR_SEXP:
+	{
+	  SEXP* px = (SEXP*) r_dataptr(ptr_x,offset,sizeof(SEXP*));
+	  *px = value_x;
+	}
+	break;
+	default: error("invalid signature");
+  }
+  return R_NilValue;
+}
+
+/** ---------------------------------------------------------------------------
+ ** C-Function: r_unpack
+ ** Description: unpack elements from C-like structures to R values.
+ ** R-Calling Convention: .Call
+ **
+ **/
+SEXP r_unpack(SEXP ptr_x, SEXP offset, SEXP sig_x)
+{
+  char* ptr = NULL;
+  const char* sig = CHAR(STRING_ELT(sig_x,0) );
+  switch(sig[0])
+  {
+    case DC_SIGCHAR_BOOL:
+      ptr = r_dataptr(ptr_x,offset,sizeof(Rboolean));
+      return ScalarLogical( ((int*)ptr)[0] );
+    case DC_SIGCHAR_CHAR:     
+      ptr = r_dataptr(ptr_x,offset,sizeof(char));
+      return ScalarInteger( ( (char*)ptr)[0] );
+    case DC_SIGCHAR_UCHAR:
+      ptr = r_dataptr(ptr_x,offset,sizeof(unsigned char));
+      return ScalarInteger( ( (unsigned char*)ptr)[0] );
+    case DC_SIGCHAR_SHORT:
+      ptr = r_dataptr(ptr_x,offset,sizeof(short));
+      return ScalarInteger( ( (short*)ptr)[0] );
+    case DC_SIGCHAR_USHORT:
+      ptr = r_dataptr(ptr_x,offset,sizeof(unsigned short));
+      return ScalarInteger( ( (unsigned short*)ptr)[0] );
+    case DC_SIGCHAR_INT:
+      ptr = r_dataptr(ptr_x,offset,sizeof(int));
+      return ScalarInteger( ( (int*)ptr )[0] );
+    case DC_SIGCHAR_UINT:
+      ptr = r_dataptr(ptr_x,offset,sizeof(unsigned int));
+      return ScalarReal( (double) ( (unsigned int*)ptr )[0] );
+    case DC_SIGCHAR_LONG:
+      ptr = r_dataptr(ptr_x,offset,sizeof(long));
+      return ScalarReal( (double) ( (long*)ptr )[0] );
+    case DC_SIGCHAR_ULONG:
+      ptr = r_dataptr(ptr_x,offset,sizeof(unsigned long));
+      return ScalarReal( (double) ( (unsigned long*) ptr )[0] );
+    case DC_SIGCHAR_FLOAT:
+      ptr = r_dataptr(ptr_x,offset,sizeof(float));
+      return ScalarReal( (double) ( (float*) ptr )[0] );
+    case DC_SIGCHAR_DOUBLE:
+      ptr = r_dataptr(ptr_x,offset,sizeof(double));
+      return ScalarReal( ((double*)ptr)[0] );
+    case DC_SIGCHAR_LONGLONG:
+      ptr = r_dataptr(ptr_x,offset,sizeof(long long));
+      return ScalarReal( (double) ( ((long long*)ptr)[0] ) );
+    case DC_SIGCHAR_ULONGLONG:
+      ptr = r_dataptr(ptr_x,offset,sizeof(unsigned long long));
+      return ScalarReal( (double) ( ((unsigned long long*)ptr)[0] ) );
+    case '*':
+    case DC_SIGCHAR_POINTER:  
+      ptr = r_dataptr(ptr_x,offset,sizeof(void*));
+      return R_MakeExternalPtr( ((void**)ptr)[0] , R_NilValue, R_NilValue );
+    case DC_SIGCHAR_STRING:   {
+      ptr = r_dataptr(ptr_x,offset,sizeof(char*));
+    	char* s = ( (char**) ptr )[0];
+		if (s == NULL) return R_MakeExternalPtr( 0, R_NilValue, R_NilValue );
+		return mkString(s);
+    }
+    case DC_SIGCHAR_SEXP:     
+      return (SEXP) ptr;
+    default: error("invalid signature");
+  }
+  return R_NilValue;
+}