Cython: How to make an array of functions with different signatures
In Cython I would like to store an array of functions, but the functions don't all have the same signature. Specifically, some have two parameters and some three.
I defined the following:
ctypedef long (*func2param)(long param1, long param2) ctypedef long (*funct3param)(long param1, long param2, long param3)
However, even if I had just one such signature, I'm still not sure how to go about making it work. Trying to assign a cdef function to an array of one of the above types gives me:
func_array2[i] = func_list[i][FUNCTION] Cannot convert Python object to 'func2param'
Trying to cast gives:
func_array2[i] = <func2param>func_list[i][FUNCTION] Python objects cannot be cast to pointers of primitive types
I can't think of anything useful you can do with an array of function pointers of unknown type - it isn't safe to call them (since you don't know the signature) and there really isn't anything else to do with function pointers. Therefore you at least need to find some way of storing what type of pointer it is.
One option would be to store a struct containing both pointers:
cdef struct FuncPtrStruct: func2param f2p func3param f3p
You then set one to
NULL, store in the other one, and only call the non-
NULLone The array specification would then be similar to
cdef FuncPtrStruct array.
However, I'd probably use a C Union instead to store both pointers in the same memory location (+ an enum to identify the type). This is a little more effort to set up (you need an
enumto define the type of the
unionitself, and a
union); however the advantage is that you can add a lot more different types of function pointers without using more memory (for the "two-type" case the memory is probably equal):
# cpdef if you want to use the enum from Python too cdef enum FuncType: twoArg, threeArg cdef union FuncPtrUnion: func2param f2p func3param f3p cdef struct FuncPtrHolder: FuncType type_ FuncPtrUnion value
Just to illustrate how you'd use it:
cdef long f(long x1, long x2): print("f",x1,x2) return 0 cdef long g(long x1, long x2, long x3): print("g",x1,x2,x3) return 1 def example(): cdef FuncPtrHolder fArray for i in range(10): if i%2: fArray[i].type_ = twoArg fArray[i].value.f2p = &f else: fArray[i].type_ = threeArg fArray[i].value.f3p = &g # use for i in range(10): if fArray[i].type_ == twoArg: fArray[i].value.f2p(i,i+1) elif fArray[i].type_ == threeArg: fArray[i].value.f3p(i,i+1,i+2)
It looks like in your code you have some
listof Python objects and this is why you're getting compile errors. Without code it's impossible to know why, but I think Cython can automatically generate Python wrappers for
cdeffunctions so I'd guess you've somehow made a list of those wrappers. If you want to handle Python lists of
FuncPtrHolder(or otherwise use it from Python) you'd have to wrap it in a