[Pyrex] Is this example correct?

Edward C. Jones edcjones at erols.com
Tue May 6 00:18:15 CEST 2003


Is the code below correct? Can I reduce the number of calls to malloc? 
Any ideas for improvement?

-------------------------
example.h:

typedef union _Num{
     int i;
     float x;
} Num;

typedef struct _Small {
     double x;
     double y;
} Small;

typedef struct _AAA {
     int k;
     Num* nump;
     Num num;
     Small small;
} AAA;

-------------------------
example.c:

#include "example.h"

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

ctypedef int size_t

cdef extern from "stdlib.h":
     void* malloc(size_t size)
     void free(void* ptr)

cdef extern from "Python.h":
     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)

cdef class OpaquePtr:
     cdef void* p

     def __new__(self):
         self.p = NULL

     def __repr__(self):
         if self.p == NULL:
             return '<OpaquePtr NULL>'
         else:
             # Ugly. Cast a pointer to an int. Not portable.
             i = <int> self.p
             return '<OpaquePtr %x>' % i

cdef wrap_ptr(void* p):
     cdef OpaquePtr P
     P = OpaquePtr()
     P.p = p
     return P

cdef void* extract_ptr(OpaquePtr P):
     return P.p

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

include "tools.pyx"

cdef extern from "example.h":

     cdef union _Num:
         int i
         float x
     ctypedef _Num Num

     cdef struct _Small:
         double x
         double y
     ctypedef _Small Small

     cdef struct _AAA:
         int k
         Num * nump
         Num  num
         Small small
     ctypedef _AAA AAA

#==============================================================

cdef class TemP__Num:
     cdef Num* t

     def __new__(self, i=0, x=0.0):
         self.t = <Num*> malloc(sizeof(Num))
         print '<malloc called for Num>'
         if self.t == NULL:
             raise MemoryError
         if i != 0 and x != 0.0:
             raise TypeError, 'both i and x are non-zero'
         if x != 0.0:
             self.t.x = x
         else:
             self.t.i = i

     def __dealloc__(self):
         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)

     def ToPointer(self):
         return  PyCObject_FromVoidPtrAndDesc(self.t, 'type Num*', NULL)

#==================================================================

cdef class TemP__Small:
     cdef Small* t

     def __new__(self, x, y):
         self.t = <Small*> malloc(sizeof(Small))
         print '<malloc called for Small>'
         sys.stdout.flush()
         if self.t == NULL:
             raise MemoryError
         self.t.x = x
         self.t.y = y

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

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

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

     def ToPointer(self):
         return  PyCObject_FromVoidPtrAndDesc(self.t, 'type Small*', NULL)

#==================================================================

cdef class TemP__AAA:
     cdef AAA* t

     def __new__(self, k, num, small):
         self.t = <AAA*> malloc(sizeof(AAA))
         print '<malloc called for AAA>'
         if self.t == NULL:
             raise MemoryError
         self.t.k = k
         self.t.nump = NULL
         self.t.num.i = num.i
         self.t.small.x = small.x
         self.t.small.y = small.y

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

     def __getattr__(self, name):
         if name == 'k':
             return self.t.k
         if name == 'nump':
             return wrap_ptr(self.t.nump)
         if name == 'num':
             return TemP__Num(self.t.num.i)
         if name == 'small':
             return TemP__Small(self.t.small.x, self.t.small.y)
         return object.__getattribute__(self, name)

     def __setattr__(self, name, val):
         if name == 'k':
             self.t.k = val
         if name == 'nump':
             self.t.nump = <Num *> extract_ptr(val)
         elif name == 'num':
             self.t.num.i = val.i
         elif name == 'small':
             self.t.small.x = val.x
             self.t.small.y = val.y
         else:
             object.__setattr__(self, name, val)

     def ToPointer(self):
         return  PyCObject_FromVoidPtrAndDesc(self.t, 'type AAA*', NULL)

-------------------------
outer.py:

from wrapped import *

Num = TemP__Num
del TemP__Num
AAA = TemP__AAA
del TemP__AAA

-------------------------
test.py:

#! /usr/bin/env python

import outer

num = outer.Num(0, 1.3)
print 'num.i:', num.i, 'num.x:', num.x
small = outer.Small(3.14159, 2.718)
aaa = outer.AAA(11, num, small)
print 'aaa.k', aaa.k
print 'aaa.num.i', aaa.num.i
print 'aaa.num.x', aaa.num.x
print 'aaa.small.x', aaa.small.x
print 'aaa.small.y', aaa.small.y

numi = outer.Num(33, 0.0)
aaa.num = numi
small2 = outer.Small(37.37, 48.48)
aaa.small = small2
print 'aaa.k', aaa.k
print 'aaa.num.i', aaa.num.i
print 'aaa.num.x', aaa.num.x
print 'aaa.small.x', aaa.small.x
print 'aaa.small.y', aaa.small.y

-------------------------
makeit:

if pyrexc wrapped.pyx
then {
     if gcc -c -fPIC -I/usr/include/python2.2/ wrapped.c
     then {
         gcc -c -fPIC example.c;
         gcc -shared example.o wrapped.o -o wrapped.so;
     } fi;
} fi;

-------------------------
Output when test.py is run:

<malloc called for Num>
num.i: 1067869798 num.x: 1.29999995232
<malloc called for Small>
<malloc called for AAA>
aaa.k 11
aaa.num.i <malloc called for Num>
1067869798
aaa.num.x <malloc called for Num>
1.29999995232
aaa.small.x <malloc called for Small>
3.14159
aaa.small.y <malloc called for Small>
2.718
<malloc called for Num>
<malloc called for Small>
aaa.k 11
aaa.num.i <malloc called for Num>
33
aaa.num.x <malloc called for Num>
4.62428493227e-44
aaa.small.x <malloc called for Small>
37.37
aaa.small.y <malloc called for Small>
48.48





More information about the Pyrex mailing list