aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-10-21 16:12:43 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-11-08 08:14:26 +0100
commit5bfcf4b6613a364ee13d0cb5e865bb6582ab7dbb (patch)
treeff1d2f21854d8aaa036aa900730610c6061687a9
parenta7a8138bae00ef1aecafed04a8ac265a9c6f07ff (diff)
shiboken6: Add predefined templates for standard container type conversion
Add some predefined XML templates with common conversions for various container types (STL and Qt) and PyLong. Remove the primitive type QModelIndexList since QModelIndexList is just a typedef. As a drive-by: - Fix a bug in cppmultihash_to_pymap_conversion which would not handle multiple keys correctly (insert several times due to iterator kit not moved past the range). - Simplify the pySequenceToCppContainer conversion by using PyIter_Next(). [ChangeLog][shiboken6] Pre-defined XML templates for standard container type conversion have been added. Task-number: PYSIDE-1666 Change-Id: Ic2e36a75f26853651718e27e0788a37519393322 Reviewed-by: Christian Tismer <tismer@stackless.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r--sources/pyside6/PySide6/QtCore/typesystem_core_common.xml79
-rw-r--r--sources/pyside6/PySide6/glue/qtcore.cpp16
-rw-r--r--sources/pyside6/PySide6/templates/core_common.xml110
-rw-r--r--sources/shiboken6/ApiExtractor/CMakeLists.txt1
-rw-r--r--sources/shiboken6/ApiExtractor/predefined_templates.cpp247
-rw-r--r--sources/shiboken6/ApiExtractor/predefined_templates.h45
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.cpp11
-rw-r--r--sources/shiboken6/ApiExtractor/typedatabase.h1
-rw-r--r--sources/shiboken6/doc/typesystem_specifying_types.rst6
-rw-r--r--sources/shiboken6/doc/typesystem_templates.rst71
-rw-r--r--sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml16
-rw-r--r--sources/shiboken6/tests/samplebinding/typesystem_sample.xml46
12 files changed, 430 insertions, 219 deletions
diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
index 473d3065a..2ee01c5a9 100644
--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
@@ -187,7 +187,9 @@
<conversion-rule>
<native-to-target file="../glue/qtcore.cpp" snippet="return-pylong"/>
<target-to-native>
- <add-conversion type="PyLong" file="../glue/qtcore.cpp" snippet="conversion-pylong"/>
+ <add-conversion type="PyLong">
+ <insert-template name="shiboken_conversion_pylong_to_cpp"/>
+ </add-conversion>
</target-to-native>
</conversion-rule>
</primitive-type>
@@ -203,7 +205,9 @@
<conversion-rule>
<native-to-target file="../glue/qtcore.cpp" snippet="return-pylong"/>
<target-to-native>
- <add-conversion type="PyLong" file="../glue/qtcore.cpp" snippet="conversion-pylong"/>
+ <add-conversion type="PyLong">
+ <insert-template name="shiboken_conversion_pylong_to_cpp"/>
+ </add-conversion>
</target-to-native>
</conversion-rule>
</primitive-type>
@@ -267,13 +271,13 @@
<include file-name="QStringList" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_conversion">
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist">
<replace from="%INTYPE_0" to="QString"/>
</insert-template>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_conversion">
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve">
<replace from="%OUTTYPE_0" to="QString"/>
</insert-template>
</add-conversion>
@@ -336,33 +340,16 @@
</conversion-rule>
</value-type>
- <primitive-type name="QModelIndexList">
- <include file-name="qabstractitemmodel.h" location="global"/>
- <conversion-rule>
- <native-to-target>
- <insert-template name="cpplist_to_pylist_conversion">
- <replace from="%INTYPE_0" to="QModelIndex"/>
- </insert-template>
- </native-to-target>
- <target-to-native>
- <add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_conversion">
- <replace from="%OUTTYPE_0" to="QModelIndex"/>
- </insert-template>
- </add-conversion>
- </target-to-native>
- </conversion-rule>
- </primitive-type>
-
<container-type name="QSet" type="set">
<include file-name="QSet" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_conversion"/>
+ <!-- FIXME PYSIDE 7: shiboken_conversion_cppsequence_to_pyset -->
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_conversion"/>
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsetcontainer"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -382,11 +369,11 @@
<!-- operator << needs to be declared in inheriting class -->
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_conversion"/>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_conversion"/>
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -396,11 +383,11 @@
<include file-name="QStack" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_conversion"/>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_conversion"/>
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -410,11 +397,11 @@
<include file-name="QQueue" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_conversion"/>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_conversion"/>
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -426,11 +413,11 @@
<include file-name="pysideqflags.h" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cppmap_to_pymap_conversion"/>
+ <insert-template name="shiboken_conversion_qmap_to_pydict"/>
</native-to-target>
<target-to-native>
<add-conversion type="PyDict">
- <insert-template name="pydict_to_cppmap_conversion"/>
+ <insert-template name="shiboken_conversion_pydict_to_qmap"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -442,11 +429,11 @@
<include file-name="pysideqflags.h" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cppmultihash_to_pymap_conversion"/>
+ <insert-template name="shiboken_conversion_qmultihash_to_pydict"/>
</native-to-target>
<target-to-native>
<add-conversion type="PyDict">
- <insert-template name="pydict_to_cppmultimap_conversion"/>
+ <insert-template name="shiboken_conversion_pydict_to_qmultihash"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -456,11 +443,11 @@
<include file-name="QMap" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cppmap_to_pymap_conversion"/>
+ <insert-template name="shiboken_conversion_qmap_to_pydict"/>
</native-to-target>
<target-to-native>
<add-conversion type="PyDict">
- <insert-template name="pydict_to_cppmap_conversion"/>
+ <insert-template name="shiboken_conversion_pydict_to_qmap"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -469,11 +456,11 @@
<include file-name="QMultiMap" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cppmultimap_to_pymap_conversion"/>
+ <insert-template name="shiboken_conversion_qmultimap_to_pydict"/>
</native-to-target>
<target-to-native>
<add-conversion type="PyDict">
- <insert-template name="pydict_to_cppmultimap_conversion"/>
+ <insert-template name="shiboken_conversion_pydict_to_qmultihash"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -482,9 +469,13 @@
<container-type name="QPair" type="pair">
<include file-name="QPair" location="global"/>
<conversion-rule>
- <native-to-target file="../glue/qtcore.cpp" snippet="return-qpair"/>
+ <native-to-target>
+ <insert-template name="shiboken_conversion_cpppair_to_pytuple"/>
+ </native-to-target>
<target-to-native>
- <add-conversion type="PySequence" file="../glue/qtcore.cpp" snippet="conversion-qpair-pysequence"/>
+ <add-conversion type="PySequence">
+ <insert-template name="shiboken_conversion_pysequence_to_cpppair"/>
+ </add-conversion>
</target-to-native>
</conversion-rule>
</container-type>
@@ -492,9 +483,13 @@
<!-- QPair is implemented with std::pair since Qt 6 -->
<container-type name="std::pair" type="pair">
<conversion-rule>
- <native-to-target file="../glue/qtcore.cpp" snippet="return-qpair"/>
+ <native-to-target>
+ <insert-template name="shiboken_conversion_cpppair_to_pytuple"/>
+ </native-to-target>
<target-to-native>
- <add-conversion type="PySequence" file="../glue/qtcore.cpp" snippet="conversion-qpair-pysequence"/>
+ <add-conversion type="PySequence">
+ <insert-template name="shiboken_conversion_pysequence_to_cpppair"/>
+ </add-conversion>
</target-to-native>
</conversion-rule>
</container-type>
diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
index 76b0ec0d7..7229fd378 100644
--- a/sources/pyside6/PySide6/glue/qtcore.cpp
+++ b/sources/pyside6/PySide6/glue/qtcore.cpp
@@ -1669,10 +1669,6 @@ if (PyErr_WarnEx(PyExc_DeprecationWarning,
%out = %OUTTYPE(%in == Py_True);
// @snippet conversion-pybool
-// @snippet conversion-pylong
-%out = %OUTTYPE(PyLong_AsLong(%in));
-// @snippet conversion-pylong
-
// @snippet conversion-pylong-quintptr
#if QT_POINTER_SIZE == 8
%out = %OUTTYPE(PyLong_AsUnsignedLongLong(%in));
@@ -1782,11 +1778,6 @@ QJsonValue val = QJsonValue::fromVariant(dict);
%out = val.toObject();
// @snippet conversion-qjsonobject-pydict
-// @snippet conversion-qpair-pysequence
-%out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0));
-%out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1));
-// @snippet conversion-qpair-pysequence
-
// @snippet conversion-qdate-pydate
int day = PyDateTime_GET_DAY(%in);
int month = PyDateTime_GET_MONTH(%in);
@@ -1912,13 +1903,6 @@ QVariant ret = val.toVariant();
return %CONVERTTOPYTHON[QVariant](ret);
// @snippet return-qjsonobject
-// @snippet return-qpair
-PyObject *%out = PyTuple_New(2);
-PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first));
-PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second));
-return %out;
-// @snippet return-qpair
-
// @snippet qthread_pthread_cleanup
#ifdef Q_OS_UNIX
# include <stdio.h>
diff --git a/sources/pyside6/PySide6/templates/core_common.xml b/sources/pyside6/PySide6/templates/core_common.xml
index abc0d6425..e26771461 100644
--- a/sources/pyside6/PySide6/templates/core_common.xml
+++ b/sources/pyside6/PySide6/templates/core_common.xml
@@ -301,38 +301,6 @@
%PYARG_0 = Py_BuildValue("%TT_FORMAT", %TT_ARGS);
</template>
- <template name="cpplist_to_pylist_conversion">
- PyObject *%out = PyList_New(Py_ssize_t(%in.size()));
- Py_ssize_t idx = 0;
- for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it, ++idx) {
- const auto &amp;cppItem = *it;
- PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
- }
- return %out;
- </template>
-
- <template name="pyseq_to_cpplist_conversion">
- // PYSIDE-795: Turn all sequences into iterables.
- if (PyList_Check(%in)) {
- const Py_ssize_t size = PySequence_Size(%in);
- if (size &gt; 10)
- (%out).reserve(size);
- }
-
- Shiboken::AutoDecRef it(PyObject_GetIter(%in));
- PyObject *(*iternext)(PyObject *) = *Py_TYPE(it)->tp_iternext;
- for (;;) {
- Shiboken::AutoDecRef pyItem(iternext(it));
- if (pyItem.isNull()) {
- if (PyErr_Occurred() &amp;&amp; PyErr_ExceptionMatches(PyExc_StopIteration))
- PyErr_Clear();
- break;
- }
- %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
- %out &lt;&lt; cppItem;
- }
- </template>
-
<template name="checkPyCapsuleOrPyCObject_func">
static bool checkPyCapsuleOrPyCObject(PyObject* pyObj)
{
@@ -340,84 +308,6 @@
}
</template>
- <template name="cppmap_to_pymap_conversion">
- PyObject *%out = PyDict_New();
- for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
- const auto &amp;key = it.key();
- const auto &amp;value = it.value();
- PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
- PyObject *pyValue = %CONVERTTOPYTHON[%INTYPE_1](value);
- PyDict_SetItem(%out, pyKey, pyValue);
- Py_DECREF(pyKey);
- Py_DECREF(pyValue);
- }
- return %out;
- </template>
-
- <template name="pydict_to_cppmap_conversion">
- PyObject *key;
- PyObject *value;
- Py_ssize_t pos = 0;
- while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
- %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
- %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
- %out.insert(cppKey, cppValue);
- }
- </template>
-
- <template name="cppmultimap_to_pymap_conversion">
- PyObject *%out = PyDict_New();
- for (auto it = %in.cbegin(), end = %in.cend(); it != end; ) {
- const auto &amp;key = it.key();
- PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
- %INTYPE::const_iterator keyEnd = %in.upperBound(key);
- const auto count = Py_ssize_t(std::distance(it, keyEnd));
- PyObject *pyValues = PyList_New(count);
- Py_ssize_t idx = 0;
- for ( ; it != keyEnd; ++it, ++idx) {
- const auto &amp;cppItem = it.value();
- PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem));
- }
- PyDict_SetItem(%out, pyKey, pyValues);
- Py_DECREF(pyKey);
- }
- return %out;
- </template>
-
- <template name="cppmultihash_to_pymap_conversion">
- PyObject *%out = PyDict_New();
- for (auto kit = %in.keyBegin(), end = %in.keyEnd(); kit != end; ++kit) {
- const auto &amp;key = *kit;
- PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
- auto range = %in.equal_range(key);
- const auto count = Py_ssize_t(std::distance(range.first, range.second));
- PyObject *pyValues = PyList_New(count);
- Py_ssize_t idx = 0;
- for (auto it = range.first; it != range.second; ++it, ++idx) {
- const auto &amp;cppItem = it.value();
- PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem));
- }
- PyDict_SetItem(%out, pyKey, pyValues);
- Py_DECREF(pyKey);
- }
- return %out;
- </template>
-
- <template name="pydict_to_cppmultimap_conversion">
- PyObject *key;
- PyObject *values;
- Py_ssize_t pos = 0;
- while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;values)) {
- %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
- const Py_ssize_t size = PySequence_Size(values);
- for (Py_ssize_t i = 0; i &lt; size; ++i) {
- Shiboken::AutoDecRef value(PySequence_GetItem(values, i));
- %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
- %out.insert(cppKey, cppValue);
- }
- }
- </template>
-
<template name="pydatetime_importandcheck_function">
static bool PyDateTime_ImportAndCheck(PyObject *pyIn)
{
diff --git a/sources/shiboken6/ApiExtractor/CMakeLists.txt b/sources/shiboken6/ApiExtractor/CMakeLists.txt
index 37f929531..1c20a8f2f 100644
--- a/sources/shiboken6/ApiExtractor/CMakeLists.txt
+++ b/sources/shiboken6/ApiExtractor/CMakeLists.txt
@@ -24,6 +24,7 @@ enclosingclassmixin.cpp
fileout.cpp
messages.cpp
modifications.cpp
+predefined_templates.cpp
propertyspec.cpp
reporthandler.cpp
sourcelocation.cpp
diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.cpp b/sources/shiboken6/ApiExtractor/predefined_templates.cpp
new file mode 100644
index 000000000..8545c2cd3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/predefined_templates.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "predefined_templates.h"
+
+static QString pySequenceToCppContainer(const QString &insertFunc,
+ bool reserve)
+{
+ QString result;
+ if (reserve) {
+ result += uR"(if (PyList_Check(%in)) {
+ const Py_ssize_t size = PySequence_Size(%in);
+ if (size > 10)
+ (%out).reserve(size);
+}
+
+)"_qs;
+ }
+
+ result += uR"(Shiboken::AutoDecRef it(PyObject_GetIter(%in));
+while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
+ (%out).)"_qs;
+
+ result += insertFunc;
+ result += uR"((cppItem);
+}
+)"_qs;
+ return result;
+}
+
+static const char stlMapKeyAccessor[] = "->first";
+static const char stlMapValueAccessor[] = "->second";
+static const char qtMapKeyAccessor[] = ".key()";
+static const char qtMapValueAccessor[] = ".value()";
+
+static QString cppMapToPyDict(bool isQMap)
+{
+ return uR"(PyObject *%out = PyDict_New();
+for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
+ const auto &key = it)"_qs
+ + QLatin1String(isQMap ? qtMapKeyAccessor : stlMapKeyAccessor)
+ + uR"(;
+ const auto &value = it)"_qs
+ + QLatin1String(isQMap ? qtMapValueAccessor : stlMapValueAccessor)
+ + uR"(;
+ PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
+ PyObject *pyValue = %CONVERTTOPYTHON[%INTYPE_1](value);
+ PyDict_SetItem(%out, pyKey, pyValue);
+ Py_DECREF(pyKey);
+ Py_DECREF(pyValue);
+}
+return %out;
+)"_qs;
+}
+
+static QString pyDictToCppMap(bool isQMap)
+{
+ return uR"(PyObject *key;
+PyObject *value;
+Py_ssize_t pos = 0;
+while (PyDict_Next(%in, &pos, &key, &value)) {
+ %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
+ %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
+ %out.insert()"_qs
+ // STL needs a pair
+ + (isQMap ? u"cppKey, cppValue"_qs : u"{cppKey, cppValue}"_qs) + uR"();
+}
+)"_qs;
+}
+
+// Convert a STL or Qt multi map to Dict of Lists using upperBound()
+static QString cppMultiMapToPyDict(bool isQMultiMap)
+{
+ return uR"(PyObject *%out = PyDict_New();
+ for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
+ const auto &key = it)"_qs
+ + QLatin1String(isQMultiMap ? qtMapKeyAccessor : stlMapKeyAccessor)
+ + uR"(;
+ PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
+ auto upper = %in.)"_qs
+ + (isQMultiMap ? u"upperBound"_qs : u"upper_bound"_qs)
+ + uR"((key);
+ const auto count = Py_ssize_t(std::distance(it, upper));
+ PyObject *pyValues = PyList_New(count);
+ Py_ssize_t idx = 0;
+ for (; it != upper; ++it, ++idx) {
+ const auto &cppItem = it.value();
+ PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem));
+ }
+ PyDict_SetItem(%out, pyKey, pyValues);
+ Py_DECREF(pyKey);
+ }
+ return %out;
+)"_qs;
+}
+
+// Convert a STL or Qt multi hash to Dict of Lists using equalRange()
+static QString cppMultiHashToPyDict(bool isQMultiHash)
+{
+ return uR"(PyObject *%out = PyDict_New();
+ for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
+ const auto &key = it)"_qs
+ + QLatin1String(isQMultiHash ? qtMapKeyAccessor : stlMapKeyAccessor)
+ + uR"(;
+ PyObject *pyKey = %CONVERTTOPYTHON[%INTYPE_0](key);
+ auto range = %in.equal_range(key);
+ const auto count = Py_ssize_t(std::distance(range.first, range.second));
+ PyObject *pyValues = PyList_New(count);
+ Py_ssize_t idx = 0;
+ for (; it != range.second; ++it, ++idx) {
+ const auto &cppItem = it.value();
+ PyList_SET_ITEM(pyValues, idx, %CONVERTTOPYTHON[%INTYPE_1](cppItem));
+ }
+ PyDict_SetItem(%out, pyKey, pyValues);
+ Py_DECREF(pyKey);
+ }
+ return %out;
+)"_qs;
+}
+
+// Convert Dict of Lists to a STL or Qt multi hash/map
+static QString pyDictToCppMultiHash(bool isQMultiHash)
+{
+ return uR"(PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(%in, &pos, &key, &values)) {
+ %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ Shiboken::AutoDecRef value(PySequence_GetItem(values, i));
+ %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
+ %out.insert()"_qs
+ + (isQMultiHash ? u"cppKey, cppValue"_qs : u"{cppKey, cppValue}"_qs)
+ + uR"();
+ }
+ }
+)"_qs;
+}
+
+const PredefinedTemplates &predefinedTemplates()
+{
+ static const PredefinedTemplates result{
+ {u"shiboken_conversion_pylong_to_cpp"_qs,
+ u"%out = %OUTTYPE(PyLong_AsLong(%in));\n"_qs},
+
+ // QPair/std::pair
+ {u"shiboken_conversion_pysequence_to_cpppair"_qs,
+ uR"(%out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0));
+%out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1));
+)"_qs},
+
+ {u"shiboken_conversion_cpppair_to_pytuple"_qs,
+ uR"(PyObject *%out = PyTuple_New(2);
+PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first));
+PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second));
+return %out;
+)"_qs},
+
+ // Sequential containers
+ {u"shiboken_conversion_cppsequence_to_pylist"_qs,
+ uR"(PyObject *%out = PyList_New(Py_ssize_t(%in.size()));
+Py_ssize_t idx = 0;
+for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it, ++idx) {
+ const auto &cppItem = *it;
+ PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+}
+return %out;)"_qs},
+
+ // PySet
+ {u"shiboken_conversion_cppsequence_to_pyset"_qs,
+ uR"(PyObject *%out = PySet_New(nullptr);
+for (const auto &cppItem : %in) {
+ PySet_Add(%out, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
+}
+return %out;)"_qs},
+
+ {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer"_qs,
+ pySequenceToCppContainer(u"push_back"_qs, false)},
+ {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"_qs,
+ pySequenceToCppContainer(u"push_back"_qs, true)},
+ {u"shiboken_conversion_pyiterable_to_cppsetcontainer"_qs,
+ pySequenceToCppContainer(u"insert"_qs, false)},
+
+ // Maps
+ {u"shiboken_conversion_stdmap_to_pydict"_qs,
+ cppMapToPyDict(false)},
+ {u"shiboken_conversion_qmap_to_pydict"_qs,
+ cppMapToPyDict(true)},
+ {u"shiboken_conversion_pydict_to_stdmap"_qs,
+ pyDictToCppMap(false)},
+ {u"shiboken_conversion_pydict_to_qmap"_qs,
+ pyDictToCppMap(true)},
+
+ // Multi maps
+ {u"shiboken_conversion_stdmultimap_to_pydict"_qs,
+ cppMultiMapToPyDict(false)},
+ {u"shiboken_conversion_qmultimap_to_pydict"_qs,
+ cppMultiMapToPyDict(true)},
+
+ // Multi hashes
+ {u"shiboken_conversion_stdunorderedmultimap_to_pydict"_qs,
+ cppMultiHashToPyDict(false)},
+ {u"shiboken_conversion_qmultihash_to_pydict"_qs,
+ cppMultiHashToPyDict(true)},
+
+ // STL multi hash/map
+ {u"shiboken_conversion_pydict_to_stdmultimap"_qs,
+ pyDictToCppMultiHash(false)},
+ {u"shiboken_conversion_pydict_to_qmultihash"_qs,
+ pyDictToCppMultiHash(true)}
+ };
+
+ return result;
+}
diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.h b/sources/shiboken6/ApiExtractor/predefined_templates.h
new file mode 100644
index 000000000..8c23fa3cf
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/predefined_templates.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PREDEFINED_TEMPLATES_H
+#define PREDEFINED_TEMPLATES_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+struct PredefinedTemplate
+{
+ QString name;
+ QString content;
+};
+
+using PredefinedTemplates = QList<PredefinedTemplate>;
+
+const PredefinedTemplates &predefinedTemplates();
+
+#endif // PREDEFINED_TEMPLATES_H
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp
index 12a89662b..65cb2b7ec 100644
--- a/sources/shiboken6/ApiExtractor/typedatabase.cpp
+++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp
@@ -31,6 +31,7 @@
#include "typesystem.h"
#include "typesystemparser.h"
#include "conditionalstreamreader.h"
+#include "predefined_templates.h"
#include <QtCore/QFile>
#include <QtCore/QDebug>
@@ -105,6 +106,9 @@ TypeDatabase::TypeDatabase()
addBuiltInType(new VarargsTypeEntry());
for (const auto &pt : builtinPythonTypes())
addBuiltInType(new PythonTypeEntry(pt.name, pt.checkFunction, pt.type));
+
+ for (const auto &p : predefinedTemplates())
+ addTemplate(p.name, p.content);
}
TypeDatabase::~TypeDatabase() = default;
@@ -592,6 +596,13 @@ void TypeDatabase::addTemplate(TemplateEntry *t)
m_templates[t->name()] = t;
}
+void TypeDatabase::addTemplate(const QString &name, const QString &code)
+{
+ auto *te = new TemplateEntry(name);
+ te->addCode(code);
+ addTemplate(te);
+}
+
void TypeDatabase::addGlobalUserFunctions(const AddedFunctionList &functions)
{
m_globalUserFunctions << functions;
diff --git a/sources/shiboken6/ApiExtractor/typedatabase.h b/sources/shiboken6/ApiExtractor/typedatabase.h
index 2eab21f32..d57433dbf 100644
--- a/sources/shiboken6/ApiExtractor/typedatabase.h
+++ b/sources/shiboken6/ApiExtractor/typedatabase.h
@@ -172,6 +172,7 @@ public:
TemplateEntry *findTemplate(const QString &name) const { return m_templates[name]; }
void addTemplate(TemplateEntry *t);
+ void addTemplate(const QString &name, const QString &code);
AddedFunctionList globalUserFunctions() const { return m_globalUserFunctions; }
diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
index ade5e5aa6..527a4cff7 100644
--- a/sources/shiboken6/doc/typesystem_specifying_types.rst
+++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
@@ -176,6 +176,9 @@ primitive-type
be instantiated and passed to functions using the view class
for argument types.
+ See :ref:`predefined_templates` for built-in templates for standard type
+ conversion rules.
+
.. _namespace:
namespace-type
@@ -474,6 +477,9 @@ container-type
The *optional* **since** value is used to specify the API version of this container.
+ See :ref:`predefined_templates` for built-in templates for standard type
+ conversion rules.
+
.. _typedef-type:
typedef-type
diff --git a/sources/shiboken6/doc/typesystem_templates.rst b/sources/shiboken6/doc/typesystem_templates.rst
index 795c9d97e..a0f52972a 100644
--- a/sources/shiboken6/doc/typesystem_templates.rst
+++ b/sources/shiboken6/doc/typesystem_templates.rst
@@ -56,3 +56,74 @@ replace
This node will replace the attribute ``from`` with the value pointed by
``to``.
+.. _predefined_templates:
+
+Predefined Templates
+--------------------
+
+There are a number of XML templates for conversion rules for STL and Qt types
+built into shiboken.
+
+Templates for :ref:`primitive-type`:
+
+ +---------------------------------------+--------------------------------+
+ |Name | Description |
+ +---------------------------------------+--------------------------------+
+ | ``shiboken_conversion_pylong_to_cpp`` | Convert a PyLong to a C++ type |
+ +---------------------------------------+--------------------------------+
+
+Templates for :ref:`container-type`:
+
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pysequence_to_cpppair`` | Convert a PySequence to a C++ pair (std::pair/QPair) |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_cpppair_to_pytuple`` | Convert a C++ pair (std::pair/QPair) to a PyTuple |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_cppsequence_to_pylist`` | Convert a C++ sequential container to a PyList |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_cppsequence_to_pyset`` | Convert a C++ sequential container to a PySet |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pyiterable_to_cppsequentialcontainer`` | Convert an iterable Python type to a C++ sequential container (STL/Qt) |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve`` | Convert an iterable Python type to a C++ sequential container supporting reserve() |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pyiterable_to_cppsetcontainer`` | Convert a PySequence to a set-type C++ container (std::set/QSet) |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_stdmap_to_pydict`` | Convert a std::map/std::unordered_map to a PyDict |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_qmap_to_pydict`` | Convert a QMap/QHash to a PyDict |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pydict_to_stdmap`` | Convert a PyDict to a std::map/std::unordered_map |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pydict_to_qmap`` | Convert a PyDict to a QMap/QHash |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_stdmultimap_to_pydict`` | Convert a std::multimap to a PyDict of value lists |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_qmultimap_to_pydict`` | Convert a QMultiMap to a PyDict of value lists |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_stdunorderedmultimap_to_pydict`` | Convert a std::unordered_multimap to a PyDict of value lists |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_qmultihash_to_pydict`` | Convert a QMultiHash to a PyDict of value lists |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pydict_to_stdmultimap`` | Convert a PyDict of value lists to std::multimap/std::unordered_multimap |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+ | ``shiboken_conversion_pydict_to_qmultihash`` | Convert a PyDict of value lists to QMultiMap/QMultiHash |
+ +----------------------------------------------------------------------+------------------------------------------------------------------------------------+
+
+An entry for the type ``std::list`` using these templates looks like:
+
+.. code-block:: xml
+
+ <container-type name="std::list" type="list">
+ <include file-name="list" location="global"/>
+ <conversion-rule>
+ <native-to-target>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type="PySequence">
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </container-type>
diff --git a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
index 9bb7e7b7e..7dd0a3a50 100644
--- a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
+++ b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml
@@ -20,23 +20,11 @@
<include file-name="list" location="global"/>
<conversion-rule>
<native-to-target>
- PyObject* %out = PyList_New(Py_ssize_t(%in.size()));
- Py_ssize_t idx = 0;
- for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it, ++idx) {
- %INTYPE_0 cppItem(*it);
- PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem));
- }
- return %out;
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0));
- const Py_ssize_t size = PySequence_Fast_GET_SIZE(seq.object());
- for (Py_ssize_t i = 0; i &lt; size; ++i) {
- PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i);
- %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
- %out.push_back(cppItem);
- }
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
</add-conversion>
</target-to-native>
</conversion-rule>
diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
index effadbc54..dd0d5f6e0 100644
--- a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
+++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml
@@ -351,20 +351,16 @@
<include file-name="utility" location="global"/>
<conversion-rule>
<native-to-target>
- PyObject* %out = PyTuple_New(2);
- PyTuple_SET_ITEM(%out, 0, %CONVERTTOPYTHON[%INTYPE_0](%in.first));
- PyTuple_SET_ITEM(%out, 1, %CONVERTTOPYTHON[%INTYPE_1](%in.second));
- return %out;
+ <insert-template name="shiboken_conversion_cpppair_to_pytuple"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- %out.first = %CONVERTTOCPP[%OUTTYPE_0](PySequence_Fast_GET_ITEM(%in, 0));
- %out.second = %CONVERTTOCPP[%OUTTYPE_1](PySequence_Fast_GET_ITEM(%in, 1));
+ <insert-template name="shiboken_conversion_pysequence_to_cpppair"/>
</add-conversion>
</target-to-native>
</conversion-rule>
</container-type>
- <template name="cpplist_to_pylist_convertion">
+ <template name="cpp_indexed_list_to_pylist_conversion">
PyObject *%out = PyList_New(Py_ssize_t(%in.size()));
Py_ssize_t idx = 0;
for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it, ++idx) {
@@ -373,24 +369,15 @@
}
return %out;
</template>
- <template name="pyseq_to_cpplist_convertion">
- Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0));
- const Py_ssize_t size = PySequence_Fast_GET_SIZE(seq.object());
- for (Py_ssize_t i = 0; i &lt; size; ++i) {
- PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i);
- %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem);
- %out.push_back(cppItem);
- }
- </template>
<container-type name="std::list" type="list">
<include file-name="list" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_convertion"/>
+ <insert-template name="shiboken_conversion_cppsequence_to_pylist"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_convertion"/>
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -399,11 +386,11 @@
<include file-name="list" location="global"/>
<conversion-rule>
<native-to-target>
- <insert-template name="cpplist_to_pylist_convertion"/>
+ <insert-template name="cpp_indexed_list_to_pylist_conversion"/>
</native-to-target>
<target-to-native>
<add-conversion type="PySequence">
- <insert-template name="pyseq_to_cpplist_convertion"/>
+ <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/>
</add-conversion>
</target-to-native>
</conversion-rule>
@@ -412,26 +399,11 @@
<include file-name="map" location="global"/>
<conversion-rule>
<native-to-target>
- PyObject* %out = PyDict_New();
- for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it) {
- %INTYPE_0 key = it->first;
- %INTYPE_1 value = it->second;
- PyDict_SetItem(%out,
- %CONVERTTOPYTHON[%INTYPE_0](key),
- %CONVERTTOPYTHON[%INTYPE_1](value));
- }
- return %out;
+ <insert-template name="shiboken_conversion_stdmap_to_pydict"/>
</native-to-target>
<target-to-native>
<add-conversion type="PyDict">
- PyObject* key;
- PyObject* value;
- Py_ssize_t pos = 0;
- while (PyDict_Next(%in, &amp;pos, &amp;key, &amp;value)) {
- %OUTTYPE_0 cppKey = %CONVERTTOCPP[%OUTTYPE_0](key);
- %OUTTYPE_1 cppValue = %CONVERTTOCPP[%OUTTYPE_1](value);
- %out.insert({cppKey, cppValue});
- }
+ <insert-template name="shiboken_conversion_pydict_to_stdmap"/>
</add-conversion>
</target-to-native>
</conversion-rule>