views:

392

answers:

3

Hello all!

I'm trying to wrap the Patricia Tries (Perl's NET::Patricia) to be exposed in python. I am having difficulty with one of the classes.

So instances the patricia node (below) as viewed from python have a "data" property. Reading it goes fine, but writing to it breaks.

typedef struct _patricia_node_t {
   u_int bit;     /* flag if this node used */
   prefix_t *prefix;     /* who we are in patricia tree */
   struct _patricia_node_t *l, *r;  /* left and right children */
   struct _patricia_node_t *parent;/* may be used */
   void *data;    /* pointer to data */
   void *user1;   /* pointer to usr data (ex. route flap info) */
} patricia_node_t;

Specifically:

>>> N = patricia.patricia_node_t()
>>> assert N.data == None
>>> N.data = 1
TypeError: in method 'patricia_node_t_data_set', argument 2 of type 'void *'

Now my C is weak. From what I read in the SWIG book, I think this means I need to pass it a pointer to data. According to the book :

Also, if you need to pass the raw pointer value to some external python library, you can do it by casting the pointer object to an integer... However, the inverse operation is not possible, i.e., you can't build a Swig pointer object from a raw integer value.

Questions:

  1. am I understanding this correctly?
  2. how do I get around this? Is %extends? typemap? Specifics would be very helpful.

Notes:

  1. I can't change the C source, but I can extend it in additional .h files or the interface .i file.
  2. From what I understand, that "data" field should be able to contain "anything" for some reasonable value of "anything" that I don't really know.
A: 

It looks like you should pass SWIG a pointer to an integer. For example, if this was all in C, your error would be like this:

void set(struct _patricia_node_t *tree, void *data) {
     tree->data = data;
}

...

int value = 1;
set(tree, &value); // OK! HOORAY!
set(tree,  value); // NOT OK! FIRE SCORPIONS!

And it seems to me you're doing the Python equivalent of set(tree, value). Now I'm not an expert with SWIG but perhaps you could pass a tuple instead of an integer? Does N.data = (1,) work? This was the answer suggested by an Allegro CL + SWIG example, but I dunno how well it applies to Python.

Hao Lian
A: 

I haven't used SWIG in a while, but I am pretty sure that you want to use a typemap that will take a PyObject* and cast it to the required void* and vice versa. Be sure to keep track of reference counts, of course.

Robert Kern
A: 

An alternative is use PyRadix, which uses the same underlying code.

Gregg Lind