If there is function pointer inside another function's parameters, how to write this Cython pxd file? - cython

In C++ header file .h, the init function is as below
void init(
void* (*image)()
, void* (*curveMappingFlat)(int)
, void* (*curveMappingImage)(int)
, void* (*colorRamp)(int)
, void* (*lightImage)(int)
);
How to write this in cython pxd file?
init(image, int, int, int, int) it will generate an error: can not convert python object to void* (*)(int)
I got stuck for a long period about this question, still can not get a solution

Related

difference in behaviour between declaration in .pyd and .pyx files

I have a pxd file that declares some types with ctypedef, and some functions with cdef. To call one particular function, I have to duplicate the typedefs in my pyx file.
If I move the cdef of the function into the pyx file it fails to compile with "Cannot convert 'state_t *' to Python object". The error refers to this line of code
retval = c_explanation.table_of_states_is_bad(<state_t*>test_array, b)
The test_array parameter is created locally with malloc so is not a python object at all.
If remove the typedefs from the pyx file and import them and the cdef from the pxd file with a from .. import *, I get the same compile error.
The only way that I can get this simple bit of code to work is with the rather awkward duplication of typedefs in both pyx and pxd files.
Any thoughts on what is going on here and how to resolve it?
The full code is pasted below
pyx file
from libc.stdlib cimport malloc, free
cimport c_explanation
cdef extern from "explanation.h":
ctypedef int state_id;
ctypedef struct event_t:
pass
ctypedef void (*event_handler)(event_t event)
ctypedef struct state_t:
state_id id
event_handler handle
char *name
ctypedef enum bool:
pass
def table_of_states_is_bad(a, b):
cdef state_t *test_array
cdef bool retval
test_array = <state_t*>malloc(len(a) * sizeof(state_t))
if not test_array:
raise MemoryError()
try:
for i, s in enumerate(a):
test_array[i].id = s[0]
retval = c_explanation.table_of_states_is_bad(test_array, b)
return retval
finally:
free(test_array)
pxd file
cdef extern from "explanation.h":
cdef int mock_get_temp(int)
ctypedef enum bool:
pass
ctypedef struct event_t:
pass
ctypedef void (*event_handler)(event_t event);
ctypedef int state_id;
ctypedef struct state_t:
state_id id
event_handler handle
char *name
cdef bool table_of_states_is_bad(state_t table[], size_t size)
finally the h file
int mock_get_temp(int);
typedef int event_id;
/* an event */
typedef struct {
event_id id; /* numeric id */
void *data; /* points to anything */
char *name; /* points to string for debug or log */
} event_t;
typedef void (*event_handler)(event_t event);
typedef enum { false, true } bool;
typedef int state_id;
/* a state */
typedef struct {
state_id id; /* numeric id */
event_handler handle; /* points to handler */
char *name; /* points to string for debug or log */
} state_t;
bool table_of_states_is_bad(state_t table[], size_t size);
After some reading and experimentation I worked out what I had done wrong.
The problem is one of namespaces. When using the import * format, the local definition of table_of_states_is_bad() was replacing the imported one. Thus the function call was to the cython version of the function rather than to the c version and hence the error was correctly reported.
I solved the problem by renaming the local function to wrap_table_of_states_is_bad() hence resolving the name conflict.

ctypedef a cython function with default arguments

I have a cython function like:
cdef void foo(int a, int b=1, int c=2):
pass
and a getter function to return its address:
def get_foo():
return <size_t>foo
so I can get function foo's address somewhere and cast it back to the real function in cython(eg: a callback one can use in python).
The problem is how to write such a type?
I tried:
cdef void foo(int a, int b=1, int c=2):
pass
ctypedef void (*foo_type)(int a, int b, int c)
cdef foo_type f = foo
this won't compile, cython complains: Cannot assign type 'void (int, struct __pyx_opt_args_46_cython_magic_49f265438c694830523a60bef4fe2ee8_foo *__pyx_optional_args)' to 'foo_type '
From the error mesage , one can note that, the option(default) arguments are wrapped in a struct by cython.
Is there a way to do such ctypedef in cython? If not, I think I'd better leave out the default value.:-(
You can create small wrappers without the default values:
cdef void foo_abc(int a, int b, int c):
foo(a,b,c)
# if you need it
cdef void foo_ab(int a, int b):
foo(a,b)
# etc
These will be convertable to function pointers:
cdef foo_type f = foo_abc
The speed loss from the wrapper functions will be small, so the main cost is just that you need to write a bit more code.

casting to const void* arguments on typdef function to use qsort in C

I have made the following typedefs in my program (C):
typedef void* ListElement;
typedef int(*CompareListElements)(ListElement, ListElement);
i have made a function pointer in my code:
CompareListElements compareElement
Later in the code i wish to use qsort on an array of ListElements:
qsort(elementsArray,listGetSize(list),sizeof(list->dummyHead->next->element, compareElement);
However the compiler states: "passing argument 4 of 'qsort' from incompatible pointer type".
I fear that it is because the qsort requires a function in the format of int (const void*, const void*). when i supply int (void*, void*).
Is there a way of casting the arguments of compareElement to (const void*, const void*), while calling qsort or before, WITHOUT changing the typedef?
Thanks
Simply cast the pointer to the appropriate type.
typedef int(*ConstCompareListElements)(const void *, const void *);
qsort(elementsArray,listGetSize(list),sizeof(list->dummyHead->next->element,
(ConstCompareListElements)compareElement);

Auto Conversion of Structs to Dicts in Cython

So, if you've got a header file.
%%file test.h
struct mystruct{
int i;
int j;
};
And then you wrap it in Cython:
cdef extern from "test.h" nogil:
struct mystruct:
int i
int j
And some function that returns back out to Py:
def spit_out_dict():
return mystruct(5,10)
Cython correctly automatically generates a dict wrapper. However, when I wrap the original C header in a namespace, I haven't been able to get get Cython to still generate the dict wrapper correctly, something along these lines:
%%file test2.h
namespace outerspace{
struct mystruct{
int i;
int j;
};
}
And Cython/Python:
cdef extern from "test2.h" namespace "outerspace" nogil:
struct mynewstruct:
int i
int j
def spit_out_dict():
return mynewstruct(5,10)
This won't compile -- lots of namespace complaint errors -- anyone experienced this before?
Your problem is that Cython seems to only expect namespaces to be used with cppclass. For structs, it generates some functions but just copies the full namespaced name in, causing errors:
static PyObject* __pyx_convert__to_py_outerspace::mystruct(struct outerspace::mystruct s);
^
py_bit.cpp: In function ‘PyObject* __pyx_pf_6py_bit_spit_out_dict(PyObject*)’:
py_bit.cpp:721:15: error: ‘__pyx_convert__to_py_outerspace’ has not been declared
where it's trying to create a function called __pyx_convert__to_py_<classname>. (I think this might be worth submitting a bug report for.)
The trick in such circumstances is usually to lie to Cython. I create three files:
// test2.hpp
namespace outerspace{
struct mystruct{
int i;
int j;
};
}
,
// test2_cy.hpp - a wrapper file purely for Cython's benefit
#include "test2.hpp"
using outerpsace::mystruct;
and the cython file
cdef extern from "test2_cy.hpp": # (I didn't test with "nogil", but it's probably fine...)
struct mynewstruct:
int i
int j
def spit_out_dict():
# for some reason using "return mystruct(5,10)" doesn't work, but this does...
cdef mystruct a = mystruct(5,10)
return a
This is a bug in Cython, fixed at https://github.com/cython/cython/commit/fa946e8435a4dcc3497fc7b0f4e87256d40844ba

__cdecl wrapping WinSock function as callback in plain C and call it

Have prepared such function, where some WSA functions will be used as callback:
int StartWinSock(int (*WSAStartup)(WORD, LPWSADATA))
{
}
But when in other code, I'm trying to launch it:
StartWinSock(WSAStartup);
I'm getting an error:
'WSClient::StartWinSock' : cannot convert parameter 1 from 'int (__stdcall *)(WORD,LPWSADATA)' to 'int (__cdecl *)(WORD,LPWSADATA)'
Also, I don't know how to pass parameters correctly through callback function like WSAStartup() ( its parameters: WORD ( unsigned short number of version ) && LPWSADATA ( reference to WSAData ) ).
You are missing the __stdcall calling convention on the function pointer type, which comes from the WINAPI macro. The compiler is therefore assuming the default __cdecl calling convention for this pointer. The two calling conventions are not compatible.
Consider creating this typedef:
typedef int WINAPI (*WSAStartupCallback)(WORD, LPWSADATA);
Then declare your function like this:
int StartWinSock(WSAStartupCallback wsaStartup)
{
}
You should then be able to call this function with the external WSAStartup pointer.