[Pyrex] Wrapping a nested struct (once more)

Edward C. Jones edcjones at erols.com
Tue Jun 10 04:00:03 CEST 2003


Here is how to wrap a nested struct using Pyrex without changing the 
original header file. The nasty secret is the "void *" in 
"TemP__Overlap_ToC" and "TemP__Overlap_FromC". Suppose the original 
header file is "nested.h". I add the file "overlap.h". The wrapper is 
"wrapper.pyx".

The code has been only superficially debugged.

Is there a better way of doing this?

--------------------
overlap.h:

typedef union {
     int i;
     float x;
} Overlap;

--------------------
nested.h

typedef struct {
     union {
         int i;
         float x;
     } overlap;
} Nest;

--------------------
nested.c:

#include "nested.h"

--------------------
tools.pyx:

ctypedef int size_t

cdef extern from "stdio.h":
     int printf(char* format, ...)

cdef extern from "Python.h":
     void* PyMem_Malloc(size_t n)
     void PyMem_Free(void *p)

     int PyCObject_Check(object p)
     object PyCObject_FromVoidPtr(void* cobj, void (*destr)(void *))
     object PyCObject_FromVoidPtrAndDesc(void* cobj, void* desc,
             void (*destr)(void *, void *))
     void* PyCObject_AsVoidPtr(object self)
     void* PyCObject_GetDesc(object self)

# These 2 functions are NOT ENOUGH for pointers. "char*" has two standard
# meanings. "AAA*" may be a pointer to AAA or an array of AAA. Etc.
cdef wrap_ptr(void* p, char* ctypename):
     return PyCObject_FromVoidPtrAndDesc(p, ctypename, NULL)

cdef void* extract_ptr(object PY):
     if PY is None:
         return NULL
     return PyCObject_AsVoidPtr(PY)

--------------------
wrapped.pyx:

include "tools.pyx"

cdef extern from "overlap.h":
     ctypedef union Overlap:
         int i
         float x

cdef extern from "nested.h":
     ctypedef struct Nest:
         Overlap overlap

cdef class TemP__Overlap:
     cdef Overlap* t

     def __new__(self, obj):
         self.t = <Overlap*> PyMem_Malloc(sizeof(Overlap))
         if self.t == NULL:
             raise MemoryError
         if isinstance(obj, int):
             self.t.i = obj
         elif isinstance(obj, float):
             self.t.x = obj
         else:
             raise TypeError, 'input type wrong'

     def __dealloc__(self):
         PyMem_Free(self.t)

     def __getattr__(self, name):
         if name == 'i':
             return self.t.i
         if name == 'x':
             return self.t.x
         return object.__getattribute__(self, name)

     def __setattr__(self, name, val):
         if name == 'i':
             self.t.i = val
         elif name == 'x':
             self.t.x = val
         else:
             object.__setattr__(self, name, val)

# The "void *" quiets a gcc warning: "passing arg 2 of
# `__pyx_f_TemP__Overlap_ToC' from incompatible pointer type".
cdef TemP__Overlap_ToC(TemP__PY, void * TemP__ptr):
     (<Overlap*> TemP__ptr).i = TemP__PY.i

# Same here.
cdef TemP__Overlap_FromC(void * TemP__ptr):
     TemP__PY0 = (<Overlap*> TemP__ptr).i
     return TemP__Overlap(TemP__PY0, TemP__PY1)

cdef class TemP__Nest:
     cdef Nest* t

     def __new__(self, overlap):
         self.t = <Nest*> PyMem_Malloc(sizeof(Nest))
         if self.t == NULL:
             raise MemoryError
         cdef int LocaLi
         cdef int LocaLj
         TemP__Overlap_ToC(overlap, &self.t.overlap)

     def __dealloc__(self):
         PyMem_Free(self.t)

     def __getattr__(self, name):
         if name == 'overlap':
             return TemP__Overlap_FromC(&self.t.overlap)
         return object.__getattribute__(self, name)

     def __setattr(self, name, val):
         if name == 'overlap':
             TemP__Overlap_ToC(val, &self.t.overlap)
         else:
             object.__setattr__(self, name, val)

cdef TemP__Nest_ToC(TemP__PY, Nest * TemP__ptr):
     TemP__Overlap_ToC(TemP__PY.overlap, &TemP__ptr.overlap)

cdef TemP__Nest_FromC(Nest * TemP__ptr):
     TemP__PY0 = TemP__Overlap_FromC(&TemP__ptr.overlap)
     return TemP__Nest(TemP__PY0)

def fun(x):
     cdef Nest n
     n.overlap.x = x
     return n.overlap.i

--------------------
somake:

cp nested.pyrex wrapped.pyx
if pyrexc wrapped.pyx &> nested.errors
then {
     if gcc -c -fPIC -I/usr/include/python2.2/ wrapped.c
     then {
         gcc -c -fPIC nested.c
         gcc -shared nested.o wrapped.o -L/usr/local/lib -o wrapped.so
     } fi;
} fi





More information about the Pyrex mailing list