Chris@87: #define FORTRANOBJECT_C Chris@87: #include "fortranobject.h" Chris@87: Chris@87: #ifdef __cplusplus Chris@87: extern "C" { Chris@87: #endif Chris@87: Chris@87: /* Chris@87: This file implements: FortranObject, array_from_pyobj, copy_ND_array Chris@87: Chris@87: Author: Pearu Peterson Chris@87: $Revision: 1.52 $ Chris@87: $Date: 2005/07/11 07:44:20 $ Chris@87: */ Chris@87: Chris@87: int Chris@87: F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj) Chris@87: { Chris@87: if (obj==NULL) { Chris@87: fprintf(stderr, "Error loading %s\n", name); Chris@87: if (PyErr_Occurred()) { Chris@87: PyErr_Print(); Chris@87: PyErr_Clear(); Chris@87: } Chris@87: return -1; Chris@87: } Chris@87: return PyDict_SetItemString(dict, name, obj); Chris@87: } Chris@87: Chris@87: /************************* FortranObject *******************************/ Chris@87: Chris@87: typedef PyObject *(*fortranfunc)(PyObject *,PyObject *,PyObject *,void *); Chris@87: Chris@87: PyObject * Chris@87: PyFortranObject_New(FortranDataDef* defs, f2py_void_func init) { Chris@87: int i; Chris@87: PyFortranObject *fp = NULL; Chris@87: PyObject *v = NULL; Chris@87: if (init!=NULL) /* Initialize F90 module objects */ Chris@87: (*(init))(); Chris@87: if ((fp = PyObject_New(PyFortranObject, &PyFortran_Type))==NULL) return NULL; Chris@87: if ((fp->dict = PyDict_New())==NULL) return NULL; Chris@87: fp->len = 0; Chris@87: while (defs[fp->len].name != NULL) fp->len++; Chris@87: if (fp->len == 0) goto fail; Chris@87: fp->defs = defs; Chris@87: for (i=0;ilen;i++) Chris@87: if (fp->defs[i].rank == -1) { /* Is Fortran routine */ Chris@87: v = PyFortranObject_NewAsAttr(&(fp->defs[i])); Chris@87: if (v==NULL) return NULL; Chris@87: PyDict_SetItemString(fp->dict,fp->defs[i].name,v); Chris@87: } else Chris@87: if ((fp->defs[i].data)!=NULL) { /* Is Fortran variable or array (not allocatable) */ Chris@87: if (fp->defs[i].type == NPY_STRING) { Chris@87: int n = fp->defs[i].rank-1; Chris@87: v = PyArray_New(&PyArray_Type, n, fp->defs[i].dims.d, Chris@87: NPY_STRING, NULL, fp->defs[i].data, fp->defs[i].dims.d[n], Chris@87: NPY_FARRAY, NULL); Chris@87: } Chris@87: else { Chris@87: v = PyArray_New(&PyArray_Type, fp->defs[i].rank, fp->defs[i].dims.d, Chris@87: fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_FARRAY, Chris@87: NULL); Chris@87: } Chris@87: if (v==NULL) return NULL; Chris@87: PyDict_SetItemString(fp->dict,fp->defs[i].name,v); Chris@87: } Chris@87: Py_XDECREF(v); Chris@87: return (PyObject *)fp; Chris@87: fail: Chris@87: Py_XDECREF(v); Chris@87: return NULL; Chris@87: } Chris@87: Chris@87: PyObject * Chris@87: PyFortranObject_NewAsAttr(FortranDataDef* defs) { /* used for calling F90 module routines */ Chris@87: PyFortranObject *fp = NULL; Chris@87: fp = PyObject_New(PyFortranObject, &PyFortran_Type); Chris@87: if (fp == NULL) return NULL; Chris@87: if ((fp->dict = PyDict_New())==NULL) return NULL; Chris@87: fp->len = 1; Chris@87: fp->defs = defs; Chris@87: return (PyObject *)fp; Chris@87: } Chris@87: Chris@87: /* Fortran methods */ Chris@87: Chris@87: static void Chris@87: fortran_dealloc(PyFortranObject *fp) { Chris@87: Py_XDECREF(fp->dict); Chris@87: PyMem_Del(fp); Chris@87: } Chris@87: Chris@87: Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: #else Chris@87: static PyMethodDef fortran_methods[] = { Chris@87: {NULL, NULL} /* sentinel */ Chris@87: }; Chris@87: #endif Chris@87: Chris@87: Chris@87: static PyObject * Chris@87: fortran_doc (FortranDataDef def) { Chris@87: char *p; Chris@87: /* Chris@87: p is used as a buffer to hold generated documentation strings. Chris@87: A common operation in generating the documentation strings, is Chris@87: appending a string to the buffer p. Earlier, the following Chris@87: idiom was: Chris@87: Chris@87: sprintf(p, "%s", p); Chris@87: Chris@87: but this does not work when _FORTIFY_SOURCE=2 is enabled: instead Chris@87: of appending the string, the string is inserted. Chris@87: Chris@87: As a fix, the following idiom should be used for appending Chris@87: strings to a buffer p: Chris@87: Chris@87: sprintf(p + strlen(p), ""); Chris@87: */ Chris@87: PyObject *s = NULL; Chris@87: int i; Chris@87: unsigned size=100; Chris@87: if (def.doc!=NULL) Chris@87: size += strlen(def.doc); Chris@87: p = (char*)malloc (size); Chris@87: p[0] = '\0'; /* make sure that the buffer has zero length */ Chris@87: if (def.rank==-1) { Chris@87: if (def.doc==NULL) { Chris@87: if (sprintf(p,"%s - ",def.name)==0) goto fail; Chris@87: if (sprintf(p+strlen(p),"no docs available")==0) Chris@87: goto fail; Chris@87: } else { Chris@87: if (sprintf(p+strlen(p),"%s",def.doc)==0) Chris@87: goto fail; Chris@87: } Chris@87: } else { Chris@87: PyArray_Descr *d = PyArray_DescrFromType(def.type); Chris@87: if (sprintf(p+strlen(p),"'%c'-",d->type)==0) { Chris@87: Py_DECREF(d); Chris@87: goto fail; Chris@87: } Chris@87: Py_DECREF(d); Chris@87: if (def.data==NULL) { Chris@87: if (sprintf(p+strlen(p),"array(%" NPY_INTP_FMT,def.dims.d[0])==0) Chris@87: goto fail; Chris@87: for(i=1;i0) { Chris@87: if (sprintf(p+strlen(p),"array(%"NPY_INTP_FMT,def.dims.d[0])==0) Chris@87: goto fail; Chris@87: for(i=1;isize) { Chris@87: fprintf(stderr,"fortranobject.c:fortran_doc:len(p)=%zd>%d(size):"\ Chris@87: " too long doc string required, increase size\n",\ Chris@87: strlen(p),size); Chris@87: goto fail; Chris@87: } Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: s = PyUnicode_FromString(p); Chris@87: #else Chris@87: s = PyString_FromString(p); Chris@87: #endif Chris@87: fail: Chris@87: free(p); Chris@87: return s; Chris@87: } Chris@87: Chris@87: static FortranDataDef *save_def; /* save pointer of an allocatable array */ Chris@87: static void set_data(char *d,npy_intp *f) { /* callback from Fortran */ Chris@87: if (*f) /* In fortran f=allocated(d) */ Chris@87: save_def->data = d; Chris@87: else Chris@87: save_def->data = NULL; Chris@87: /* printf("set_data: d=%p,f=%d\n",d,*f); */ Chris@87: } Chris@87: Chris@87: static PyObject * Chris@87: fortran_getattr(PyFortranObject *fp, char *name) { Chris@87: int i,j,k,flag; Chris@87: if (fp->dict != NULL) { Chris@87: PyObject *v = PyDict_GetItemString(fp->dict, name); Chris@87: if (v != NULL) { Chris@87: Py_INCREF(v); Chris@87: return v; Chris@87: } Chris@87: } Chris@87: for (i=0,j=1;ilen && (j=strcmp(name,fp->defs[i].name));i++); Chris@87: if (j==0) Chris@87: if (fp->defs[i].rank!=-1) { /* F90 allocatable array */ Chris@87: if (fp->defs[i].func==NULL) return NULL; Chris@87: for(k=0;kdefs[i].rank;++k) Chris@87: fp->defs[i].dims.d[k]=-1; Chris@87: save_def = &fp->defs[i]; Chris@87: (*(fp->defs[i].func))(&fp->defs[i].rank,fp->defs[i].dims.d,set_data,&flag); Chris@87: if (flag==2) Chris@87: k = fp->defs[i].rank + 1; Chris@87: else Chris@87: k = fp->defs[i].rank; Chris@87: if (fp->defs[i].data !=NULL) { /* array is allocated */ Chris@87: PyObject *v = PyArray_New(&PyArray_Type, k, fp->defs[i].dims.d, Chris@87: fp->defs[i].type, NULL, fp->defs[i].data, 0, NPY_FARRAY, Chris@87: NULL); Chris@87: if (v==NULL) return NULL; Chris@87: /* Py_INCREF(v); */ Chris@87: return v; Chris@87: } else { /* array is not allocated */ Chris@87: Py_INCREF(Py_None); Chris@87: return Py_None; Chris@87: } Chris@87: } Chris@87: if (strcmp(name,"__dict__")==0) { Chris@87: Py_INCREF(fp->dict); Chris@87: return fp->dict; Chris@87: } Chris@87: if (strcmp(name,"__doc__")==0) { Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: PyObject *s = PyUnicode_FromString(""), *s2, *s3; Chris@87: for (i=0;ilen;i++) { Chris@87: s2 = fortran_doc(fp->defs[i]); Chris@87: s3 = PyUnicode_Concat(s, s2); Chris@87: Py_DECREF(s2); Chris@87: Py_DECREF(s); Chris@87: s = s3; Chris@87: } Chris@87: #else Chris@87: PyObject *s = PyString_FromString(""); Chris@87: for (i=0;ilen;i++) Chris@87: PyString_ConcatAndDel(&s,fortran_doc(fp->defs[i])); Chris@87: #endif Chris@87: if (PyDict_SetItemString(fp->dict, name, s)) Chris@87: return NULL; Chris@87: return s; Chris@87: } Chris@87: if ((strcmp(name,"_cpointer")==0) && (fp->len==1)) { Chris@87: PyObject *cobj = F2PyCapsule_FromVoidPtr((void *)(fp->defs[0].data),NULL); Chris@87: if (PyDict_SetItemString(fp->dict, name, cobj)) Chris@87: return NULL; Chris@87: return cobj; Chris@87: } Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: if (1) { Chris@87: PyObject *str, *ret; Chris@87: str = PyUnicode_FromString(name); Chris@87: ret = PyObject_GenericGetAttr((PyObject *)fp, str); Chris@87: Py_DECREF(str); Chris@87: return ret; Chris@87: } Chris@87: #else Chris@87: return Py_FindMethod(fortran_methods, (PyObject *)fp, name); Chris@87: #endif Chris@87: } Chris@87: Chris@87: static int Chris@87: fortran_setattr(PyFortranObject *fp, char *name, PyObject *v) { Chris@87: int i,j,flag; Chris@87: PyArrayObject *arr = NULL; Chris@87: for (i=0,j=1;ilen && (j=strcmp(name,fp->defs[i].name));i++); Chris@87: if (j==0) { Chris@87: if (fp->defs[i].rank==-1) { Chris@87: PyErr_SetString(PyExc_AttributeError,"over-writing fortran routine"); Chris@87: return -1; Chris@87: } Chris@87: if (fp->defs[i].func!=NULL) { /* is allocatable array */ Chris@87: npy_intp dims[F2PY_MAX_DIMS]; Chris@87: int k; Chris@87: save_def = &fp->defs[i]; Chris@87: if (v!=Py_None) { /* set new value (reallocate if needed -- Chris@87: see f2py generated code for more Chris@87: details ) */ Chris@87: for(k=0;kdefs[i].rank;k++) dims[k]=-1; Chris@87: if ((arr = array_from_pyobj(fp->defs[i].type,dims,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) Chris@87: return -1; Chris@87: (*(fp->defs[i].func))(&fp->defs[i].rank,arr->dimensions,set_data,&flag); Chris@87: } else { /* deallocate */ Chris@87: for(k=0;kdefs[i].rank;k++) dims[k]=0; Chris@87: (*(fp->defs[i].func))(&fp->defs[i].rank,dims,set_data,&flag); Chris@87: for(k=0;kdefs[i].rank;k++) dims[k]=-1; Chris@87: } Chris@87: memcpy(fp->defs[i].dims.d,dims,fp->defs[i].rank*sizeof(npy_intp)); Chris@87: } else { /* not allocatable array */ Chris@87: if ((arr = array_from_pyobj(fp->defs[i].type,fp->defs[i].dims.d,fp->defs[i].rank,F2PY_INTENT_IN,v))==NULL) Chris@87: return -1; Chris@87: } Chris@87: if (fp->defs[i].data!=NULL) { /* copy Python object to Fortran array */ Chris@87: npy_intp s = PyArray_MultiplyList(fp->defs[i].dims.d,arr->nd); Chris@87: if (s==-1) Chris@87: s = PyArray_MultiplyList(arr->dimensions,arr->nd); Chris@87: if (s<0 || Chris@87: (memcpy(fp->defs[i].data,arr->data,s*PyArray_ITEMSIZE(arr)))==NULL) { Chris@87: if ((PyObject*)arr!=v) { Chris@87: Py_DECREF(arr); Chris@87: } Chris@87: return -1; Chris@87: } Chris@87: if ((PyObject*)arr!=v) { Chris@87: Py_DECREF(arr); Chris@87: } Chris@87: } else return (fp->defs[i].func==NULL?-1:0); Chris@87: return 0; /* succesful */ Chris@87: } Chris@87: if (fp->dict == NULL) { Chris@87: fp->dict = PyDict_New(); Chris@87: if (fp->dict == NULL) Chris@87: return -1; Chris@87: } Chris@87: if (v == NULL) { Chris@87: int rv = PyDict_DelItemString(fp->dict, name); Chris@87: if (rv < 0) Chris@87: PyErr_SetString(PyExc_AttributeError,"delete non-existing fortran attribute"); Chris@87: return rv; Chris@87: } Chris@87: else Chris@87: return PyDict_SetItemString(fp->dict, name, v); Chris@87: } Chris@87: Chris@87: static PyObject* Chris@87: fortran_call(PyFortranObject *fp, PyObject *arg, PyObject *kw) { Chris@87: int i = 0; Chris@87: /* printf("fortran call Chris@87: name=%s,func=%p,data=%p,%p\n",fp->defs[i].name, Chris@87: fp->defs[i].func,fp->defs[i].data,&fp->defs[i].data); */ Chris@87: if (fp->defs[i].rank==-1) {/* is Fortran routine */ Chris@87: if (fp->defs[i].func==NULL) { Chris@87: PyErr_Format(PyExc_RuntimeError, "no function to call"); Chris@87: return NULL; Chris@87: } Chris@87: else if (fp->defs[i].data==NULL) Chris@87: /* dummy routine */ Chris@87: return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw,NULL); Chris@87: else Chris@87: return (*((fortranfunc)(fp->defs[i].func)))((PyObject *)fp,arg,kw, Chris@87: (void *)fp->defs[i].data); Chris@87: } Chris@87: PyErr_Format(PyExc_TypeError, "this fortran object is not callable"); Chris@87: return NULL; Chris@87: } Chris@87: Chris@87: static PyObject * Chris@87: fortran_repr(PyFortranObject *fp) Chris@87: { Chris@87: PyObject *name = NULL, *repr = NULL; Chris@87: name = PyObject_GetAttrString((PyObject *)fp, "__name__"); Chris@87: PyErr_Clear(); Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: if (name != NULL && PyUnicode_Check(name)) { Chris@87: repr = PyUnicode_FromFormat("", name); Chris@87: } Chris@87: else { Chris@87: repr = PyUnicode_FromString(""); Chris@87: } Chris@87: #else Chris@87: if (name != NULL && PyString_Check(name)) { Chris@87: repr = PyString_FromFormat("", PyString_AsString(name)); Chris@87: } Chris@87: else { Chris@87: repr = PyString_FromString(""); Chris@87: } Chris@87: #endif Chris@87: Py_XDECREF(name); Chris@87: return repr; Chris@87: } Chris@87: Chris@87: Chris@87: PyTypeObject PyFortran_Type = { Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: PyVarObject_HEAD_INIT(NULL, 0) Chris@87: #else Chris@87: PyObject_HEAD_INIT(0) Chris@87: 0, /*ob_size*/ Chris@87: #endif Chris@87: "fortran", /*tp_name*/ Chris@87: sizeof(PyFortranObject), /*tp_basicsize*/ Chris@87: 0, /*tp_itemsize*/ Chris@87: /* methods */ Chris@87: (destructor)fortran_dealloc, /*tp_dealloc*/ Chris@87: 0, /*tp_print*/ Chris@87: (getattrfunc)fortran_getattr, /*tp_getattr*/ Chris@87: (setattrfunc)fortran_setattr, /*tp_setattr*/ Chris@87: 0, /*tp_compare/tp_reserved*/ Chris@87: (reprfunc)fortran_repr, /*tp_repr*/ Chris@87: 0, /*tp_as_number*/ Chris@87: 0, /*tp_as_sequence*/ Chris@87: 0, /*tp_as_mapping*/ Chris@87: 0, /*tp_hash*/ Chris@87: (ternaryfunc)fortran_call, /*tp_call*/ Chris@87: }; Chris@87: Chris@87: /************************* f2py_report_atexit *******************************/ Chris@87: Chris@87: #ifdef F2PY_REPORT_ATEXIT Chris@87: static int passed_time = 0; Chris@87: static int passed_counter = 0; Chris@87: static int passed_call_time = 0; Chris@87: static struct timeb start_time; Chris@87: static struct timeb stop_time; Chris@87: static struct timeb start_call_time; Chris@87: static struct timeb stop_call_time; Chris@87: static int cb_passed_time = 0; Chris@87: static int cb_passed_counter = 0; Chris@87: static int cb_passed_call_time = 0; Chris@87: static struct timeb cb_start_time; Chris@87: static struct timeb cb_stop_time; Chris@87: static struct timeb cb_start_call_time; Chris@87: static struct timeb cb_stop_call_time; Chris@87: Chris@87: extern void f2py_start_clock(void) { ftime(&start_time); } Chris@87: extern Chris@87: void f2py_start_call_clock(void) { Chris@87: f2py_stop_clock(); Chris@87: ftime(&start_call_time); Chris@87: } Chris@87: extern Chris@87: void f2py_stop_clock(void) { Chris@87: ftime(&stop_time); Chris@87: passed_time += 1000*(stop_time.time - start_time.time); Chris@87: passed_time += stop_time.millitm - start_time.millitm; Chris@87: } Chris@87: extern Chris@87: void f2py_stop_call_clock(void) { Chris@87: ftime(&stop_call_time); Chris@87: passed_call_time += 1000*(stop_call_time.time - start_call_time.time); Chris@87: passed_call_time += stop_call_time.millitm - start_call_time.millitm; Chris@87: passed_counter += 1; Chris@87: f2py_start_clock(); Chris@87: } Chris@87: Chris@87: extern void f2py_cb_start_clock(void) { ftime(&cb_start_time); } Chris@87: extern Chris@87: void f2py_cb_start_call_clock(void) { Chris@87: f2py_cb_stop_clock(); Chris@87: ftime(&cb_start_call_time); Chris@87: } Chris@87: extern Chris@87: void f2py_cb_stop_clock(void) { Chris@87: ftime(&cb_stop_time); Chris@87: cb_passed_time += 1000*(cb_stop_time.time - cb_start_time.time); Chris@87: cb_passed_time += cb_stop_time.millitm - cb_start_time.millitm; Chris@87: } Chris@87: extern Chris@87: void f2py_cb_stop_call_clock(void) { Chris@87: ftime(&cb_stop_call_time); Chris@87: cb_passed_call_time += 1000*(cb_stop_call_time.time - cb_start_call_time.time); Chris@87: cb_passed_call_time += cb_stop_call_time.millitm - cb_start_call_time.millitm; Chris@87: cb_passed_counter += 1; Chris@87: f2py_cb_start_clock(); Chris@87: } Chris@87: Chris@87: static int f2py_report_on_exit_been_here = 0; Chris@87: extern Chris@87: void f2py_report_on_exit(int exit_flag,void *name) { Chris@87: if (f2py_report_on_exit_been_here) { Chris@87: fprintf(stderr," %s\n",(char*)name); Chris@87: return; Chris@87: } Chris@87: f2py_report_on_exit_been_here = 1; Chris@87: fprintf(stderr," /-----------------------\\\n"); Chris@87: fprintf(stderr," < F2PY performance report >\n"); Chris@87: fprintf(stderr," \\-----------------------/\n"); Chris@87: fprintf(stderr,"Overall time spent in ...\n"); Chris@87: fprintf(stderr,"(a) wrapped (Fortran/C) functions : %8d msec\n", Chris@87: passed_call_time); Chris@87: fprintf(stderr,"(b) f2py interface, %6d calls : %8d msec\n", Chris@87: passed_counter,passed_time); Chris@87: fprintf(stderr,"(c) call-back (Python) functions : %8d msec\n", Chris@87: cb_passed_call_time); Chris@87: fprintf(stderr,"(d) f2py call-back interface, %6d calls : %8d msec\n", Chris@87: cb_passed_counter,cb_passed_time); Chris@87: Chris@87: fprintf(stderr,"(e) wrapped (Fortran/C) functions (acctual) : %8d msec\n\n", Chris@87: passed_call_time-cb_passed_call_time-cb_passed_time); Chris@87: fprintf(stderr,"Use -DF2PY_REPORT_ATEXIT_DISABLE to disable this message.\n"); Chris@87: fprintf(stderr,"Exit status: %d\n",exit_flag); Chris@87: fprintf(stderr,"Modules : %s\n",(char*)name); Chris@87: } Chris@87: #endif Chris@87: Chris@87: /********************** report on array copy ****************************/ Chris@87: Chris@87: #ifdef F2PY_REPORT_ON_ARRAY_COPY Chris@87: static void f2py_report_on_array_copy(PyArrayObject* arr) { Chris@87: const long arr_size = PyArray_Size((PyObject *)arr); Chris@87: if (arr_size>F2PY_REPORT_ON_ARRAY_COPY) { Chris@87: fprintf(stderr,"copied an array: size=%ld, elsize=%d\n", Chris@87: arr_size, PyArray_ITEMSIZE(arr)); Chris@87: } Chris@87: } Chris@87: static void f2py_report_on_array_copy_fromany(void) { Chris@87: fprintf(stderr,"created an array from object\n"); Chris@87: } Chris@87: Chris@87: #define F2PY_REPORT_ON_ARRAY_COPY_FROMARR f2py_report_on_array_copy((PyArrayObject *)arr) Chris@87: #define F2PY_REPORT_ON_ARRAY_COPY_FROMANY f2py_report_on_array_copy_fromany() Chris@87: #else Chris@87: #define F2PY_REPORT_ON_ARRAY_COPY_FROMARR Chris@87: #define F2PY_REPORT_ON_ARRAY_COPY_FROMANY Chris@87: #endif Chris@87: Chris@87: Chris@87: /************************* array_from_obj *******************************/ Chris@87: Chris@87: /* Chris@87: * File: array_from_pyobj.c Chris@87: * Chris@87: * Description: Chris@87: * ------------ Chris@87: * Provides array_from_pyobj function that returns a contigious array Chris@87: * object with the given dimensions and required storage order, either Chris@87: * in row-major (C) or column-major (Fortran) order. The function Chris@87: * array_from_pyobj is very flexible about its Python object argument Chris@87: * that can be any number, list, tuple, or array. Chris@87: * Chris@87: * array_from_pyobj is used in f2py generated Python extension Chris@87: * modules. Chris@87: * Chris@87: * Author: Pearu Peterson Chris@87: * Created: 13-16 January 2002 Chris@87: * $Id: fortranobject.c,v 1.52 2005/07/11 07:44:20 pearu Exp $ Chris@87: */ Chris@87: Chris@87: static int Chris@87: count_nonpos(const int rank, Chris@87: const npy_intp *dims) { Chris@87: int i=0,r=0; Chris@87: while (ind; Chris@87: npy_intp size = PyArray_Size((PyObject *)arr); Chris@87: printf("\trank = %d, flags = %d, size = %" NPY_INTP_FMT "\n", Chris@87: rank,arr->flags,size); Chris@87: printf("\tstrides = "); Chris@87: dump_dims(rank,arr->strides); Chris@87: printf("\tdimensions = "); Chris@87: dump_dims(rank,arr->dimensions); Chris@87: } Chris@87: #endif Chris@87: Chris@87: #define SWAPTYPE(a,b,t) {t c; c = (a); (a) = (b); (b) = c; } Chris@87: Chris@87: static int swap_arrays(PyArrayObject* arr1, PyArrayObject* arr2) { Chris@87: SWAPTYPE(arr1->data,arr2->data,char*); Chris@87: SWAPTYPE(arr1->nd,arr2->nd,int); Chris@87: SWAPTYPE(arr1->dimensions,arr2->dimensions,npy_intp*); Chris@87: SWAPTYPE(arr1->strides,arr2->strides,npy_intp*); Chris@87: SWAPTYPE(arr1->base,arr2->base,PyObject*); Chris@87: SWAPTYPE(arr1->descr,arr2->descr,PyArray_Descr*); Chris@87: SWAPTYPE(arr1->flags,arr2->flags,int); Chris@87: /* SWAPTYPE(arr1->weakreflist,arr2->weakreflist,PyObject*); */ Chris@87: return 0; Chris@87: } Chris@87: Chris@87: #define ARRAY_ISCOMPATIBLE(arr,type_num) \ Chris@87: ( (PyArray_ISINTEGER(arr) && PyTypeNum_ISINTEGER(type_num)) \ Chris@87: ||(PyArray_ISFLOAT(arr) && PyTypeNum_ISFLOAT(type_num)) \ Chris@87: ||(PyArray_ISCOMPLEX(arr) && PyTypeNum_ISCOMPLEX(type_num)) \ Chris@87: ||(PyArray_ISBOOL(arr) && PyTypeNum_ISBOOL(type_num)) \ Chris@87: ) Chris@87: Chris@87: extern Chris@87: PyArrayObject* array_from_pyobj(const int type_num, Chris@87: npy_intp *dims, Chris@87: const int rank, Chris@87: const int intent, Chris@87: PyObject *obj) { Chris@87: /* Note about reference counting Chris@87: ----------------------------- Chris@87: If the caller returns the array to Python, it must be done with Chris@87: Py_BuildValue("N",arr). Chris@87: Otherwise, if obj!=arr then the caller must call Py_DECREF(arr). Chris@87: Chris@87: Note on intent(cache,out,..) Chris@87: --------------------- Chris@87: Don't expect correct data when returning intent(cache) array. Chris@87: Chris@87: */ Chris@87: char mess[200]; Chris@87: PyArrayObject *arr = NULL; Chris@87: PyArray_Descr *descr; Chris@87: char typechar; Chris@87: int elsize; Chris@87: Chris@87: if ((intent & F2PY_INTENT_HIDE) Chris@87: || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None)) Chris@87: || ((intent & F2PY_OPTIONAL) && (obj==Py_None)) Chris@87: ) { Chris@87: /* intent(cache), optional, intent(hide) */ Chris@87: if (count_nonpos(rank,dims)) { Chris@87: int i; Chris@87: sprintf(mess,"failed to create intent(cache|hide)|optional array" Chris@87: "-- must have defined dimensions but got ("); Chris@87: for(i=0;ielsize; Chris@87: typechar = descr->type; Chris@87: Py_DECREF(descr); Chris@87: if (PyArray_Check(obj)) { Chris@87: arr = (PyArrayObject *)obj; Chris@87: Chris@87: if (intent & F2PY_INTENT_CACHE) { Chris@87: /* intent(cache) */ Chris@87: if (PyArray_ISONESEGMENT(obj) Chris@87: && PyArray_ITEMSIZE((PyArrayObject *)obj)>=elsize) { Chris@87: if (check_and_fix_dimensions((PyArrayObject *)obj,rank,dims)) { Chris@87: return NULL; /*XXX: set exception */ Chris@87: } Chris@87: if (intent & F2PY_INTENT_OUT) Chris@87: Py_INCREF(obj); Chris@87: return (PyArrayObject *)obj; Chris@87: } Chris@87: sprintf(mess,"failed to initialize intent(cache) array"); Chris@87: if (!PyArray_ISONESEGMENT(obj)) Chris@87: sprintf(mess+strlen(mess)," -- input must be in one segment"); Chris@87: if (PyArray_ITEMSIZE(arr)descr->type,typechar); Chris@87: if (!(F2PY_CHECK_ALIGNMENT(arr, intent))) Chris@87: sprintf(mess+strlen(mess)," -- input not %d-aligned", F2PY_GET_ALIGNMENT(intent)); Chris@87: PyErr_SetString(PyExc_ValueError,mess); Chris@87: return NULL; Chris@87: } Chris@87: Chris@87: /* here we have always intent(in) or intent(inplace) */ Chris@87: Chris@87: { Chris@87: PyArrayObject *retarr = (PyArrayObject *) \ Chris@87: PyArray_New(&PyArray_Type, arr->nd, arr->dimensions, type_num, Chris@87: NULL,NULL,0, Chris@87: !(intent&F2PY_INTENT_C), Chris@87: NULL); Chris@87: if (retarr==NULL) Chris@87: return NULL; Chris@87: F2PY_REPORT_ON_ARRAY_COPY_FROMARR; Chris@87: if (PyArray_CopyInto(retarr, arr)) { Chris@87: Py_DECREF(retarr); Chris@87: return NULL; Chris@87: } Chris@87: if (intent & F2PY_INTENT_INPLACE) { Chris@87: if (swap_arrays(arr,retarr)) Chris@87: return NULL; /* XXX: set exception */ Chris@87: Py_XDECREF(retarr); Chris@87: if (intent & F2PY_INTENT_OUT) Chris@87: Py_INCREF(arr); Chris@87: } else { Chris@87: arr = retarr; Chris@87: } Chris@87: } Chris@87: return arr; Chris@87: } Chris@87: Chris@87: if ((intent & F2PY_INTENT_INOUT) || Chris@87: (intent & F2PY_INTENT_INPLACE) || Chris@87: (intent & F2PY_INTENT_CACHE)) { Chris@87: PyErr_SetString(PyExc_TypeError, Chris@87: "failed to initialize intent(inout|inplace|cache) " Chris@87: "array, input not an array"); Chris@87: return NULL; Chris@87: } Chris@87: Chris@87: { Chris@87: F2PY_REPORT_ON_ARRAY_COPY_FROMANY; Chris@87: arr = (PyArrayObject *) \ Chris@87: PyArray_FromAny(obj,PyArray_DescrFromType(type_num), 0,0, Chris@87: ((intent & F2PY_INTENT_C)?NPY_CARRAY:NPY_FARRAY) \ Chris@87: | NPY_FORCECAST, NULL); Chris@87: if (arr==NULL) Chris@87: return NULL; Chris@87: if (check_and_fix_dimensions(arr,rank,dims)) Chris@87: return NULL; /*XXX: set exception */ Chris@87: return arr; Chris@87: } Chris@87: Chris@87: } Chris@87: Chris@87: /*****************************************/ Chris@87: /* Helper functions for array_from_pyobj */ Chris@87: /*****************************************/ Chris@87: Chris@87: static Chris@87: int check_and_fix_dimensions(const PyArrayObject* arr,const int rank,npy_intp *dims) { Chris@87: /* Chris@87: This function fills in blanks (that are -1\'s) in dims list using Chris@87: the dimensions from arr. It also checks that non-blank dims will Chris@87: match with the corresponding values in arr dimensions. Chris@87: */ Chris@87: const npy_intp arr_size = (arr->nd)?PyArray_Size((PyObject *)arr):1; Chris@87: #ifdef DEBUG_COPY_ND_ARRAY Chris@87: dump_attrs(arr); Chris@87: printf("check_and_fix_dimensions:init: dims="); Chris@87: dump_dims(rank,dims); Chris@87: #endif Chris@87: if (rank > arr->nd) { /* [1,2] -> [[1],[2]]; 1 -> [[1]] */ Chris@87: npy_intp new_size = 1; Chris@87: int free_axe = -1; Chris@87: int i; Chris@87: npy_intp d; Chris@87: /* Fill dims where -1 or 0; check dimensions; calc new_size; */ Chris@87: for(i=0;ind;++i) { Chris@87: d = arr->dimensions[i]; Chris@87: if (dims[i] >= 0) { Chris@87: if (d>1 && dims[i]!=d) { Chris@87: fprintf(stderr,"%d-th dimension must be fixed to %" NPY_INTP_FMT Chris@87: " but got %" NPY_INTP_FMT "\n", Chris@87: i,dims[i], d); Chris@87: return 1; Chris@87: } Chris@87: if (!dims[i]) dims[i] = 1; Chris@87: } else { Chris@87: dims[i] = d ? d : 1; Chris@87: } Chris@87: new_size *= dims[i]; Chris@87: } Chris@87: for(i=arr->nd;i1) { Chris@87: fprintf(stderr,"%d-th dimension must be %" NPY_INTP_FMT Chris@87: " but got 0 (not defined).\n", Chris@87: i,dims[i]); Chris@87: return 1; Chris@87: } else if (free_axe<0) Chris@87: free_axe = i; Chris@87: else Chris@87: dims[i] = 1; Chris@87: if (free_axe>=0) { Chris@87: dims[free_axe] = arr_size/new_size; Chris@87: new_size *= dims[free_axe]; Chris@87: } Chris@87: if (new_size != arr_size) { Chris@87: fprintf(stderr,"unexpected array size: new_size=%" NPY_INTP_FMT Chris@87: ", got array with arr_size=%" NPY_INTP_FMT " (maybe too many free" Chris@87: " indices)\n", new_size,arr_size); Chris@87: return 1; Chris@87: } Chris@87: } else if (rank==arr->nd) { Chris@87: npy_intp new_size = 1; Chris@87: int i; Chris@87: npy_intp d; Chris@87: for (i=0; idimensions[i]; Chris@87: if (dims[i]>=0) { Chris@87: if (d > 1 && d!=dims[i]) { Chris@87: fprintf(stderr,"%d-th dimension must be fixed to %" NPY_INTP_FMT Chris@87: " but got %" NPY_INTP_FMT "\n", Chris@87: i,dims[i],d); Chris@87: return 1; Chris@87: } Chris@87: if (!dims[i]) dims[i] = 1; Chris@87: } else dims[i] = d; Chris@87: new_size *= dims[i]; Chris@87: } Chris@87: if (new_size != arr_size) { Chris@87: fprintf(stderr,"unexpected array size: new_size=%" NPY_INTP_FMT Chris@87: ", got array with arr_size=%" NPY_INTP_FMT "\n", new_size,arr_size); Chris@87: return 1; Chris@87: } Chris@87: } else { /* [[1,2]] -> [[1],[2]] */ Chris@87: int i,j; Chris@87: npy_intp d; Chris@87: int effrank; Chris@87: npy_intp size; Chris@87: for (i=0,effrank=0;ind;++i) Chris@87: if (arr->dimensions[i]>1) ++effrank; Chris@87: if (dims[rank-1]>=0) Chris@87: if (effrank>rank) { Chris@87: fprintf(stderr,"too many axes: %d (effrank=%d), expected rank=%d\n", Chris@87: arr->nd,effrank,rank); Chris@87: return 1; Chris@87: } Chris@87: Chris@87: for (i=0,j=0;ind && arr->dimensions[j]<2) ++j; Chris@87: if (j>=arr->nd) d = 1; Chris@87: else d = arr->dimensions[j++]; Chris@87: if (dims[i]>=0) { Chris@87: if (d>1 && d!=dims[i]) { Chris@87: fprintf(stderr,"%d-th dimension must be fixed to %" NPY_INTP_FMT Chris@87: " but got %" NPY_INTP_FMT " (real index=%d)\n", Chris@87: i,dims[i],d,j-1); Chris@87: return 1; Chris@87: } Chris@87: if (!dims[i]) dims[i] = 1; Chris@87: } else Chris@87: dims[i] = d; Chris@87: } Chris@87: Chris@87: for (i=rank;ind;++i) { /* [[1,2],[3,4]] -> [1,2,3,4] */ Chris@87: while (jnd && arr->dimensions[j]<2) ++j; Chris@87: if (j>=arr->nd) d = 1; Chris@87: else d = arr->dimensions[j++]; Chris@87: dims[rank-1] *= d; Chris@87: } Chris@87: for (i=0,size=1;ind); Chris@87: for (i=0;ind;++i) fprintf(stderr," %" NPY_INTP_FMT,arr->dimensions[i]); Chris@87: fprintf(stderr," ]\n"); Chris@87: return 1; Chris@87: } Chris@87: } Chris@87: #ifdef DEBUG_COPY_ND_ARRAY Chris@87: printf("check_and_fix_dimensions:end: dims="); Chris@87: dump_dims(rank,dims); Chris@87: #endif Chris@87: return 0; Chris@87: } Chris@87: Chris@87: /* End of file: array_from_pyobj.c */ Chris@87: Chris@87: /************************* copy_ND_array *******************************/ Chris@87: Chris@87: extern Chris@87: int copy_ND_array(const PyArrayObject *arr, PyArrayObject *out) Chris@87: { Chris@87: F2PY_REPORT_ON_ARRAY_COPY_FROMARR; Chris@87: return PyArray_CopyInto(out, (PyArrayObject *)arr); Chris@87: } Chris@87: Chris@87: /*********************************************/ Chris@87: /* Compatibility functions for Python >= 3.0 */ Chris@87: /*********************************************/ Chris@87: Chris@87: #if PY_VERSION_HEX >= 0x03000000 Chris@87: Chris@87: PyObject * Chris@87: F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(PyObject *)) Chris@87: { Chris@87: PyObject *ret = PyCapsule_New(ptr, NULL, dtor); Chris@87: if (ret == NULL) { Chris@87: PyErr_Clear(); Chris@87: } Chris@87: return ret; Chris@87: } Chris@87: Chris@87: void * Chris@87: F2PyCapsule_AsVoidPtr(PyObject *obj) Chris@87: { Chris@87: void *ret = PyCapsule_GetPointer(obj, NULL); Chris@87: if (ret == NULL) { Chris@87: PyErr_Clear(); Chris@87: } Chris@87: return ret; Chris@87: } Chris@87: Chris@87: int Chris@87: F2PyCapsule_Check(PyObject *ptr) Chris@87: { Chris@87: return PyCapsule_CheckExact(ptr); Chris@87: } Chris@87: Chris@87: #else Chris@87: Chris@87: PyObject * Chris@87: F2PyCapsule_FromVoidPtr(void *ptr, void (*dtor)(void *)) Chris@87: { Chris@87: return PyCObject_FromVoidPtr(ptr, dtor); Chris@87: } Chris@87: Chris@87: void * Chris@87: F2PyCapsule_AsVoidPtr(PyObject *ptr) Chris@87: { Chris@87: return PyCObject_AsVoidPtr(ptr); Chris@87: } Chris@87: Chris@87: int Chris@87: F2PyCapsule_Check(PyObject *ptr) Chris@87: { Chris@87: return PyCObject_Check(ptr); Chris@87: } Chris@87: Chris@87: #endif Chris@87: Chris@87: Chris@87: #ifdef __cplusplus Chris@87: } Chris@87: #endif Chris@87: /************************* EOF fortranobject.c *******************************/