Cython: Nesting a union within a struct - python

In Cython glue declarations, how do I represent a C struct type containing an anonymous union? For example, if I have a C header file mystruct.h containing
struct mystruct
{
union {
double da;
uint64_t ia;
};
};
then, in the corresponding .pyd file
cdef extern from "mystruct.h":
struct mystruct:
# what goes here???
I tried this:
cdef extern from "mystruct.h":
struct mystruct:
union {double da; uint64_t ia;};
but that only gave me "Syntax error in C variable declaration" on the union line.

For those who got here via Google, I found a solution to this. If you have a struct:
typedef struct {
union {
int a;
struct {
int b;
int c;
};
}
} outer;
You can flatten it all out in the Cython declaration, like so:
ctypedef struct outer:
int a
int b
int c
Cython isn't generating any code that makes any suppositions about the memory layout of your struct; you're only telling it the de facto structure of what you're calling by telling it what syntax to generate to call it. So if your structure has a member of size int that can be accessed as ((outer) x).a, then you can throw a on the struct definition and it will work. It's operating on textual substitution, not memory layout, so it doesn't care about whether these things are in anonymous unions or structs or what have you.

You can't nest declarations to the best of my knowledge, and Cython doesn't support anonymous unions AFAIK.
Try the following:
cdef union mystruct_union:
double lower_d
uint64_t lower
cdef struct mystruct:
mystruct_union un
Now access the union members as un.lower_d and un.lower.

Related

How can you wrap a C++ function with SWIG that takes in a Python numpy array as input without explicitly giving a size?

I have a library of C++ classes that I am building a Python interface for using SWIG. Many of these classes have methods that take in a double* array or int* array parameter without inputting a size. For example, there are many methods that have a declaration like one of the following:
void func(double* array);
void func2(double* array, double unrelated_parameter, ...);
I would like to be able to use these functions in Python, with the user passing in a Python numpy array. The size of these arrays are never given as a parameter to the function. The size of the input array is given in the constructor of the objects of these C++ classes and it is assumed that every input array that is given as a parameter to these class methods will have the same size. All of the numpy examples I have seen require me to add an int array_size parameter to the C++ method/function being wrapped.
Is there a way to wrap these C++ functions without having change the API of my entire C++ library to include an int array_size parameter for every single function? Ideally, a user should pass in a Python numpy array and SWIG will automatically convert it to a double or int array on the C++ side.
I have already included numpy.i and followed the instructions here: https://numpy.org/doc/stable/reference/swig.interface-file.html but am getting errors like the following:
TypeError: in method 'func', argument 2 of type 'double *'
One way I can think of is to suppress the "no size" version of the function and extend the class to have a version with a throw-away dimension variable that uses the actual parameter in the class.
Example:
test.i
%module test
%{
#define SWIG_FILE_WITH_INIT
class Test {
public:
int _dim; // needs to be public, or have a public accessor.
Test(int dim) : _dim(dim) {}
double func(double* array) {
double sum = 0.0;
for(int i = 0; i < _dim; ++i)
sum += array[i];
return sum;
}
};
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1, int DIM1) {(double* array, int /*unused*/)};
%ignore Test::func; // so the one-parameter version isn't wrapped
class Test {
public:
Test(int dim);
double func(double* array);
};
%rename("%s") Test::func; // unignore so the two-parameter version will be used.
%extend Test {
double func(double* array, int /*unused*/) {
return $self->func(array);
}
}
Demo:
>>> import test
>>> t = test.Test(5)
>>> import numpy as np
>>> a = np.array([1.5,2.0,2.5,3.75,4.25])
>>> t.func(a)
14.0

How to declare linked lists with pointers in Cython

I am trying to create a linked list in Cython for the following C code:
typedef struct my_struct *my_val;
typedef struct my_struct {
int i;
my_val next_val;
}
This didn't work:
cdef my_struct* my_val
cdef struct bc_struct:
int i
my_val next_val
I get this error on the first cdef:
'my_val' is not a type identifier
Neither did this:
cdef struct my_struct* my_val
This gives an error on the first cdef:
Syntax error in struct or union definition
Any help is much appreciated!
From what i have read so far cdef is not the equivalent of a typedef. Instead you are declaring C variables. Try using ctypedef instead as descriped in the link.
EDIT: A bit more explanation.
When you use cdef mystruct* my_val you are not performing a typedef, instead you are declaring the C variable my_val which is of type mystruct *. When you now try to use it as a type specifier like in your class, it of course tells you that it is not a specifier since it is a variable. If you use ctypedef instead it performs a typedef
ctypedef mystruct *my_val
for the second cdef struct mystruct* my_val it throws a syntax error because the syntax is cdef type name and thus you try to initialize a variable called mystruct* of type struct and have also a trailing my_val expression behind it.

Wrapping a C function in Cython which has non-stanard types as arguments

I am trying to wrap a C++ function that has arguments of type uint32_t, which can be found in the cstdint library. Let's say the C++ file looks like
cppfile.cpp:
#include <cstdint>
int foo(uint32_t x){
return 1;
}
How do I wrap this in a Cython .pxd file? If x was just a normal integer, I would do
cdef extern from "cppfile.cpp":
cdef int foo(int x)
But how do I do this when x is of type uint32_t? How do I obtain the uint32_t as a type in cython?
This is a question answered in the FAQ of cython
from libc.stdint cimport uint32_t
cdef extern from "cppfile.cpp":
cdef int foo(uint32_t x)

How to wrap C file with extern variables with Cython

I want to wrap a quite long C function published by a scientist with Cython. I am following
http://scipy-lectures.github.io/advanced/interfacing_with_c/interfacing_with_c.html#interfacing-with-c
and I am able to replicate the examples with numpy support.
I am confused about what to do (or to do anything at all) about variables declared as extern in the library.cpp. Obviously, I will have a main.py that will call this function, not a main.cpp. How should I declare ini_flag and A and pass to func? Is there any other way than making them arguments to the function? If possible I would prefer not to edit original library.cpp file.
// main.cpp:
int ini_flag=0, *A;
void main(){
func(...)
...
}
// library.cpp:
extern int ini_flag, *A;
void func(...){
if (ini_flag==0){
// malloc and initialize A
ini_flag=1;
}
// use A and do other stuff
}
You should create a corresponding library.hpp file:
int ini_flag, *A;
void func(...)
And then in Cython:
cdef extern from "library.hpp":
int ini_flag, *A
void func(...)
Then you can then use them normally in Cython.

Accessing C struct array to Python with SWIG

I attempting to call into existing C code from Python. The C code defines a struct B that contains an struct array of As. The C code also defines a function that puts values into the structure when called. I can access the array member variable, but it is not an list (or something that supports indexing). Instead, I am getting an object that is a proxy for B*.
I found this question, but it doesn't look like it was completely resolved. I'm also not sure how to make an instance of the Python class B to replace the PyString_FromString().
Below is the code needed to demonstrate my issue and how to execute it:
example.h
typedef struct A_s
{
unsigned int thing;
unsigned int other;
} A_t;
typedef struct B_s
{
unsigned int size;
A_t items[16];
} B_t;
unsigned int foo(B_t* b);
example.c
#include "example.h"
unsigned int
foo(B_t* b)
{
b->size = 1;
b->items[0].thing = 1;
b->items[0].other = 2;
}
example.i
%module example
%{
#define SWIG_FILE_WITH_INIT
#include "example.h"
%}
%include "example.h"
setup.py
from distutils.core import setup, Extension
module1 = Extension('example', sources=['example.c', 'example.i'])
setup(name='Example', version='0.1', ext_modules=[module1])
script.py - This uses library and demonstrates the failure.
import example
b = example.B_t()
example.foo(b)
print b.size
print b.items
for i in xrange(b.size):
print b.items[i]
How to run everything:
python setup.py build_ext --inplace
mv example.so _example.so
python script.py
you could write some C helper functions like:
int get_thing(B_t *this_b_t, int idx);
int get_other(B_t *this_b_t, int idx);
void set_thing(B_t *this_b_t, int idx, int val);
void set_other(B_t *this_b_t, int idx, int val);
wrap these and you can then use the pointer that you get from example.B_t() to access values from within your data-structure arrangement, e.g.
>>> b = example.B_t()
>>> a_thing = example.get_thing(b, 0)
>>> example.set_thing(b,0,999)
Hopefully its obvious what the implementation of these C functions should be - if not I could provide an example...
granted this isn't as seamless as being able to access C arrays as python lists - you might be able to use typemaps to achieve this but I can't remember the exact syntax you would need in this instance - you'd have to do a bit of RTFM on the SWIG documentation
also possible duplicate here: nested structure array access in python using SWIG

Categories