From a35208d9026ed91acbc12dd65b18d790a22eace0 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 19 Apr 2018 23:33:29 +0100 Subject: [PATCH] Improve QVariant conversion and generalise QMap conversion --- src/runner/pythonrunner.cpp | 113 ++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/src/runner/pythonrunner.cpp b/src/runner/pythonrunner.cpp index ee1de22..7fad240 100644 --- a/src/runner/pythonrunner.cpp +++ b/src/runner/pythonrunner.cpp @@ -181,6 +181,55 @@ struct GuessedValue_converters }; +template +struct QMap_converters +{ + struct QMap_to_python + { + static PyObject *convert(const QMap &map) { + bpy::dict result; + QMapIterator iter(map); + while (iter.hasNext()) { + iter.next(); + result[bpy::object(iter.key())] = bpy::object(iter.value()); + } + return bpy::incref(result.ptr()); + } + }; + + struct QMap_from_python + { + QMap_from_python() { + bpy::converter::registry::push_back(&convertible, &construct, bpy::type_id>()); + } + + static void *convertible(PyObject *objPtr) { + return PyDict_Check(objPtr) ? objPtr : nullptr; + } + + static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { + void *storage = ((bpy::converter::rvalue_from_python_storage>*)data)->storage.bytes; + QMap *result = new (storage) QMap(); + bpy::dict source(bpy::handle<>(bpy::borrowed(objPtr))); + bpy::list keys = source.keys(); + int len = bpy::len(keys); + for (int i = 0; i < len; ++i) { + bpy::object pyKey = keys[i]; + (*result)[bpy::extract(pyKey)] = bpy::extract(source[pyKey]); + } + + data->convertible = storage; + } + }; + + QMap_converters() + { + QMap_from_python(); + bpy::to_python_converter, QMap_to_python >(); + } +}; + + struct QVariant_to_python_obj { static PyObject *convert(const QVariant &var) { @@ -188,24 +237,12 @@ struct QVariant_to_python_obj case QVariant::Int: return PyLong_FromLong(var.toInt()); case QVariant::UInt: return PyLong_FromUnsignedLong(var.toUInt()); case QVariant::Bool: return PyBool_FromLong(var.toBool()); - case QVariant::String: return bpy::incref(bpy::object(var.toString().toUtf8().constData()).ptr()); + case QVariant::String: return bpy::incref(bpy::object(var.toString()).ptr()); case QVariant::List: { - QVariantList list = var.toList(); - PyObject *result = PyList_New(list.count()); - for (QVariant var : list) { - PyList_Append(result, convert(var)); - } - return result; + return bpy::incref(bpy::object(var.toList()).ptr()); } break; case QVariant::Map: { - QVariantMap map = var.toMap(); - PyObject *result = PyDict_New(); - QMapIterator iter(map); - while (iter.hasNext()) { - iter.next(); - PyDict_SetItem(result, convert(iter.key()), convert(iter.value())); - } - return result; + return bpy::incref(bpy::object(var.toMap()).ptr()); } break; default: { PyErr_Format(PyExc_TypeError, "type unsupported: %d", var.type()); @@ -239,49 +276,21 @@ struct QVariant_from_python_obj data->convertible = storage; } - static QVariant variantFromPyObject(PyObject *objPtr) { - QVariant result; - if (PyList_Check(objPtr)) { - QVariantList resultList; - for (int i = 0; i < PyList_Size(objPtr); ++i) { - resultList.append(variantFromPyObject(PyList_GetItem(objPtr, i))); - } - result = resultList; - } else if (PyString_Check(objPtr)) { - result = PyString_AsString(objPtr); - } else if (PyBool_Check(objPtr)) { - result = (objPtr == Py_True); - } else if (PyInt_Check(objPtr)) { - //QVariant doesn't have long. It has int or long long. Given that on m/s, - //long is 32 bits for 32- and 64- bit code... - result = static_cast(PyInt_AsLong(objPtr)); - } else { - PyErr_SetString(PyExc_TypeError, "type unsupported"); - throw bpy::error_already_set(); - } - return result; - } - static void construct(PyObject *objPtr, bpy::converter::rvalue_from_python_stage1_data *data) { // PyBools will also return true for PyInt_Check but not the other way around, so the order // here is relevant if (PyList_Check(objPtr)) { - QVariantList result; - for (int i = 0; i < PyList_Size(objPtr); ++i) { - result.append(variantFromPyObject(PyList_GetItem(objPtr, i))); - } - constructVariant(result, data); - } else if (PyString_Check(objPtr)) { - const char *value = PyString_AsString(objPtr); - constructVariant(value, data); + constructVariant(bpy::extract(objPtr)(), data); + } else if (PyDict_Check(objPtr)) { + constructVariant(bpy::extract(objPtr)(), data); + } else if (PyString_Check(objPtr) || PyUnicode_Check(objPtr)) { + constructVariant(bpy::extract(objPtr)(), data); } else if (PyBool_Check(objPtr)) { - bool value = (objPtr == Py_True); - constructVariant(value, data); + constructVariant(bpy::extract(objPtr)(), data); } else if (PyInt_Check(objPtr)) { //QVariant doesn't have long. It has int or long long. Given that on m/s, //long is 32 bits for 32- and 64- bit code... - int value = static_cast(PyInt_AsLong(objPtr)); - constructVariant(value, data); + constructVariant(bpy::extract(objPtr)(), data); } else { PyErr_SetString(PyExc_TypeError, "type unsupported"); throw bpy::error_already_set(); @@ -1095,6 +1104,10 @@ BOOST_PYTHON_MODULE(mobase) QList_from_python_obj(); bpy::to_python_converter, QList_to_python_list>(); + QList_from_python_obj(); + QList_to_python_list(); + + QMap_converters(); std_vector_from_python_obj();