简体   繁体   中英

How to translate std::list from c++ to python with SIP

I am using SIP version 6.0.1 with python 3.8 and have a given c++11 API. (on Ubuntu 18.04)

The goal is to store eg custom struct pointers (the structs I also translated with sip) in std::list using python.

I constructed a tiny example to make my case:

std_list.sip file

%Module(name=std_list, language="C++")

%Include type_list.sip

%DefaultEncoding "UTF-8"

struct TestStruct {

%TypeHeaderCode
#include <std_list.h>
%End

    int test1;
    int test2;

    void printStruct() const;
    TestStruct();
};

typedef std::list<TestStruct*> ListTestStruct;

struct StructContainerLvl2 {

%TypeHeaderCode
#include <std_list.h>
%End

    ListTestStruct listTestStruct;
    StructContainerLvl2();
};

type_list.sip file for the list translation

template<TYPE *>
%MappedType std::list<TYPE *> /TypeHint="List[TYPE]"/ {
%TypeHeaderCode
#include <list>
%End

%ConvertFromTypeCode
    PyObject *l;

    const sipTypeDef* kpTypeDef = sipFindType("TYPE");

    if (!kpTypeDef) {
        return NULL;
    }

    // Create the Python list of the correct length.
    if ((l = PyList_New(sipCpp->size())) == NULL) {
        return NULL;
    }

    int i = 0;
    for(std::list<TYPE *>::iterator iter = sipCpp->begin(); iter != sipCpp->end(); iter++) {
        TYPE *cpp = *iter;
        PyObject *pobj;

        // Get the Python wrapper for the Type instance, creating a new
        // one if necessary, and handle any ownership transfer.
        if ((pobj = sipConvertFromType(cpp, kpTypeDef, sipTransferObj)) == NULL) {
            // There was an error so garbage collect the Python list.
            Py_XDECREF(l);
            return NULL;
        }

        // Add the wrapper to the list.
        PyList_SET_ITEM(l, i++, pobj);
    }

    // Return the Python list.
    return l;
%End

%ConvertToTypeCode
    const sipTypeDef* kpTypeDef = sipFindType("TYPE");

    if (!kpTypeDef) {
        return 0;
    }

    // Check if type is compatible
    if (sipIsErr == NULL) {
        if (!PyList_Check(sipPy)) {
            return 0;
        }
        for (Py_ssize_t i = 0; i < PyList_GET_SIZE(sipPy); ++i) {
            PyObject *item = PyList_GET_ITEM(sipPy, i);
            if (!sipCanConvertToType(item, kpTypeDef, SIP_NOT_NONE)) {
                return 0;
            }
        }
        return 1;
    }
    // Convert Python list of TYPE to std::list<TYPE*>
    std::list<TYPE*> *l = new std::list<TYPE*>();

    for (Py_ssize_t i = 0; i < PyList_GET_SIZE(sipPy); ++i) {
        int state;
        PyObject *item = PyList_GET_ITEM(sipPy, i);
        TYPE* p = static_cast<TYPE*>(sipConvertToType(item, kpTypeDef, NULL, SIP_NOT_NONE, &state, sipIsErr));

        if (*sipIsErr) {
            sipReleaseType(p, kpTypeDef, state);
            delete l;
            return 0;
        }

        sipTransferTo(item, item);
        l->push_back(p);

        sipReleaseType(p, kpTypeDef, state);
    }

    *sipCppPtr = l;
    return sipGetState(sipTransferObj);
%End
};

std_list.h file

#include <list>

struct TestStruct {

    int test1{};
    int test2{};

    void printStruct() const;
    TestStruct() = default;
};

typedef std::list<TestStruct*> ListTestStruct;

struct StructContainerLvl2 {
    ListTestStruct listTestStruct;
    StructContainerLvl2() = default;
};

test.py file

import std_list

if __name__ == '__main__':

    testStruct1 = std_list.TestStruct()
    testStruct1.test1 = 1
    testStruct1.test2 = 2

    testStruct2 = std_list.TestStruct()
    testStruct2.test1 = 21
    testStruct2.test2 = 22

    temp_structContainerLvl2 = std_list.StructContainerLvl2()

    print(temp_structContainerLvl2.listTestStruct)

    temp_structContainerLvl2.listTestStruct.append(testStruct1)
    temp_structContainerLvl2.listTestStruct.append(testStruct2)

    print(temp_structContainerLvl2.listTestStruct)

    for item in temp_structContainerLvl2.listTestStruct:
        print("List item {}".format(item))
        print()

The problem is that the list is always empty. No matter what I try to store in it. The error is probably in the type_list.sip file. I updated an example I found, but I'm not sure if its right.

Can someone help?

Thanks Johnny

The problem is not in the type_list.sip file, but in the test.py file.

The cmd of appending something to a translated python list with append like...

temp_structContainerLvl2.listTestStruct.append(testStruct1)

can not be used for the sip translation of a python list.

As a workaround, one can use

temp_structContainerLvl2.listTestStruct = [testStruct1, testStruct2]

and

temp_structContainerLvl2.listTestStruct += [testStruct3]

I imagine it is not that efficient, but all I've got for now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM