3

I need to share an ArrayFire array creating in C++ to Python. That works OK:

PyObject* arrayToPyObject(const af::array& arr)
{
    // Create arrayfire array and set 
    PyObject* afArray = createObject("arrayfire", "Array");

    PyObject* ctypes_mod = PyImport_ImportModule("ctypes");
    PyObject* c_void_p = PyObject_GetAttrString(ctypes_mod, "c_void_p");
    PyObject* p = PyObject_CallFunction(c_void_p, "O", PyLong_FromVoidPtr(arr.get()));

    if (PyObject_SetAttr(afArray, PyUnicode_FromString("arr"), p) == 0)
    {
        return afArray;
    }
    else
    {
        Py_XDECREF(afArray);
        return nullptr;
    }
}

Now if my Python script return an ArrayFire array I need to read the arr attribute and get my pointer back and assign it to a C++ array

af::array pyObjectToArray(PyObject* obj)
{
    af::array tmp;
    PyObject* arr = PyObject_GetAttr(obj, PyUnicode_FromString("arr"));
    if (arr)
    {
        af_array ref = (af_array)(PyLong_AsVoidPtr(arr));

        if (ref)
        {
            tmp.set(ref);
        }
    }

    return tmp;
}

Issue here is that PyLong_AsVoidPtr failswith class 'TypeError': an integer is required.

ctypes doc (16.16.1.4. Fundamental data types) says the Python type for c_void_p is either int or None. Obviously it is None in my case

How can I convert c_void_p to python using the C API?

Thanks!

  • Curious. Any reason you are not using the Python wrapper for arrayfire ? – Pavan Yalamanchili Feb 02 '17 at 16:33
  • I am using it. But if you need to share pass an af::array created in your application to the arrayfire python binding type Array, then you'll need that trick. The good thing about passing the af_array ref is that if you are using a CUDA backend, the memory stays in GPU and you won't get overhead from copying data. – Damien LEFEVRE Feb 03 '17 at 08:09

1 Answers1

2

I solved it.

The ctypes type objects values can be read from the value attribute.

af::array pyObjectToArray(PyObject* obj)
{
    af::array tmp;
    PyObject* arr = PyObject_GetAttr(obj, PyUnicode_FromString("arr")); // <-- c_void_p object
    PyObject* p = PyObject_GetAttr(arr, PyUnicode_FromString("value") // <-- int value

    if (arr)
    {
        af_array ref = (af_array)(PyLong_AsVoidPtr(p));

        if (ref)
        {
            tmp.set(ref);
        }
    }

    return tmp;
}