File: array.c

package info (click to toggle)
rpy2 2.1.3-1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 804 kB
  • ctags: 1,754
  • sloc: ansic: 5,417; python: 4,771; makefile: 142
file content (166 lines) | stat: -rw-r--r-- 4,444 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* A. Belopolsky's Array interface */


#include <Python.h>
#include <Rdefines.h>
#include <Rinternals.h>
#include "rpy_rinterface.h"

#define ARRAY_INTERFACE_VERSION 2

/* Array Interface flags */
#define NPY_CONTIGUOUS    0x0001
#define NPY_FORTRAN       0x0002
#define NPY_ENSURECOPY    0x0020
#define NPY_ALIGNED       0x0100
#define NPY_NOTSWAPPED    0x0200
#define NPY_WRITEABLE     0x0400
#define NPY_BEHAVED       (NPY_ALIGNED | NPY_WRITEABLE)
#define NPY_FARRAY        (NPY_FORTRAN | NPY_BEHAVED)

typedef struct {
  int version;
  int nd;
  char typekind;
  int itemsize;
  int flags;
  Py_intptr_t *shape;
  Py_intptr_t *strides;
  void *data;
} PyArrayInterface;

static char
sexp_typekind(SEXP sexp)
{
  /* Given an SEXP object, this returns the corresponding
   * Type in the numpy world.
   */
  switch (TYPEOF(sexp)) {
  case REALSXP: return 'f';
  case INTSXP: return 'i';
    /* FIXME: handle strings ? */
    /* case STRSXP: return 'S'; */
    /* FIXME: handle 'O' (as R list ?) */
  case CPLXSXP: return 'c';
    /* It would be more logical (hah) to return 'b' here, but 1) R booleans are
     * full integer width, and Numpy for example can only handle 8-bit booleans,
     * not 32-bit, 2) R actually uses this width; NA_LOGICAL is the same as
     * NA_INTEGER, i.e. INT_MIN, i.e. 0x80000000. So this also lets us preserve
     * NA's: */
  case LGLSXP: return 'i';
  }
  return 0;
}

static void*
sexp_typepointer(SEXP sexp)
{
  switch (TYPEOF(sexp)) {
  case REALSXP: return (void *)NUMERIC_POINTER(sexp);
  case INTSXP: return (void *)INTEGER_POINTER(sexp);
    /* case STRSXP: return (void *)CHARACTER_POINTER(; */
  case CPLXSXP: return (void *)COMPLEX_POINTER(sexp);
  case LGLSXP: return (void *)LOGICAL_POINTER(sexp);
  }
  return NULL;
}


static int
sexp_itemsize(SEXP sexp)
{
  switch (TYPEOF(sexp)) {
  case REALSXP: return sizeof(*REAL(sexp));
  case INTSXP: return sizeof(*INTEGER(sexp));
  case STRSXP: return sizeof(*CHAR(sexp));
  case CPLXSXP: return sizeof(*COMPLEX(sexp));
  case LGLSXP: return sizeof(*LOGICAL(sexp));
  }
  return 0;
}

/* static int */
/* sexp_rank(SEXP sexp) */
/* { */
/*   /\* Return the number of dimensions for the array  */
/*    * (e.g., a vector will return 1, a matrix 2, ...) */
/*    *\/ */
/*   SEXP dim = getAttrib(sexp, R_DimSymbol); */
/*   if (dim == R_NilValue) */
/*     return 1; */
/*   return GET_LENGTH(dim); */
/* } */

/* static void */
/* sexp_shape(SEXP sexp, Py_intptr_t* shape, int nd) */
/* { */
/*   /\* Set the numpy 'shape', that is a vector of Py_intptr_t */
/*    * containing the size of each dimension (see sexp_rank). */
/*    *\/ */
/*   int i; */
/*   SEXP dim = getAttrib(sexp, R_DimSymbol); */
/*   if (dim == R_NilValue) */
/*     shape[0] = LENGTH(sexp); */
/*   else for (i = 0; i < nd; ++i) { */
/*       shape[i] = INTEGER(dim)[i]; */
/*     } */
/* } */

static void
array_struct_free(void *ptr, void *arr)
{
  PyArrayInterface *inter       = (PyArrayInterface *)ptr;
  PyMem_Free(inter->shape);
  Py_DECREF((PyObject *)arr);
  PyMem_Free(inter);
}


static PyObject* 
array_struct_get(PySexpObject *self)
{
  /* Get an array structure as understood by the numpy package from
     'self' (a SexpVector).
   */
  SEXP sexp = RPY_SEXP(self);
  if (!sexp) {
    PyErr_SetString(PyExc_AttributeError, "Null sexp");
    return NULL;
  }

  char typekind =  sexp_typekind(sexp);
  if (!typekind) {
    PyErr_SetString(PyExc_AttributeError, "Unsupported SEXP type");
    return NULL;
  }

  /* allocate memory for the array description (this is what will be returned) */
  PyArrayInterface *inter;
  inter = (PyArrayInterface *)PyMem_Malloc(sizeof(PyArrayInterface));
  if (!inter) {
    return PyErr_NoMemory();
  }

  inter->version = ARRAY_INTERFACE_VERSION;

  int nd = sexp_rank(sexp);
  inter->nd = nd;

  inter->typekind = typekind;
  inter->itemsize = sexp_itemsize(sexp);
  inter->flags = (NPY_FARRAY | NPY_NOTSWAPPED);
  inter->shape = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t)*nd);
  sexp_shape(sexp, inter->shape, nd);
  inter->strides = (Py_intptr_t*)PyMem_Malloc(sizeof(Py_intptr_t)*nd);
  sexp_strides(sexp, inter->strides, inter->itemsize,
	       inter->shape, nd);

  inter->data = sexp_typepointer(sexp);
  if (inter->data == NULL) {
    PyErr_SetString(PyExc_RuntimeError, "Error while mapping type.");
    return NULL;
  }
  Py_INCREF(self);
  return PyCObject_FromVoidPtrAndDesc(inter, self, array_struct_free);
}