[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