aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShyamnath Premnadh <Shyamnath.Premnadh@qt.io>2022-01-14 12:33:07 +0100
committerShyamnath Premnadh <Shyamnath.Premnadh@qt.io>2022-01-18 16:33:25 +0100
commit9599f4c02ec39ceb2513128fca02d148a5d00f32 (patch)
treee153c410cb0127bd70734f2631e4bc5e5cc08a92
parent56f66f128566bd08f027fee46bb42a6c4f57a26e (diff)
Improve documentation - Opaque Containers
The usage of opaque-containers through the <container-type/> attribute is hard to understand from https://doc.qt.io/qtforpython/shiboken6/typesystem_containers.html This patch adds an example to create an opaque container from std::vector<int> in C++, and use/modify this opaque container through Python. Task-number: PYSIDE-1776 Change-Id: Ieb86e38e2d666ea67194b129e16c5a9809ddb619 Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r--sources/shiboken6/doc/typesystem_containers.rst203
1 files changed, 203 insertions, 0 deletions
diff --git a/sources/shiboken6/doc/typesystem_containers.rst b/sources/shiboken6/doc/typesystem_containers.rst
index c3a60a707..f692fce30 100644
--- a/sources/shiboken6/doc/typesystem_containers.rst
+++ b/sources/shiboken6/doc/typesystem_containers.rst
@@ -59,3 +59,206 @@ the STL and the Qt naming convention (which resembles Python's) are supported:
| | that can be stored without |
| | reallocation. |
+-------------------------------------------+-----------------------------------+
+
+Following is an example on creating an opaque container named ``IntVector``
+from `std::vector<int>`, and using it in Python.
+
+We will consider three separate use cases.
+
+**Case 1** - When a Python list is passed to C++ function
+`TestOpaqueContainer.getVectorSum(const std::vector<int>&)` as an opaque container
+
+.. code-block:: c
+
+ class TestOpaqueContainer
+ {
+ public:
+ static int getVectorSum(const std::vector<int>& intVector)
+ {
+ return std::accumulate(intVector.begin(), intVector.end(), 0);
+ }
+ };
+
+**Case 2** - When we have a C++ class named `TestOpaqueContainer` with a `std::vector<int>`
+public variable
+
+.. code-block:: c
+
+ class TestOpaqueContainer
+ {
+ public:
+ std::vector<int> intVector;
+
+ };
+
+**Case 3** - When we have a C++ class named `TestOpaqueContainer` with a `std::vector<int>` as
+private variable and the variable is returned by a reference through a getter.
+
+.. code-block:: c
+
+ class TestOpaqueContainer
+ {
+ public:
+ std::vector<int>& getIntVector()
+ {
+ return this->intVector;
+ }
+
+ private:
+ std::vector<int> intVector;
+
+ };
+
+.. note:: Cases 2 and 3 are generally considered to be bad class design in C++. However, the purpose
+ of these examples are rather to show the different possibilities with opaque containers in
+ Shiboken than the class design.
+
+In all the three cases, we want to use `intVector` in Python through an opaque-container. The
+first thing to do is to create the corresponding `<container-type />` attribute in the typesystem
+file, making Shiboken aware of the `IntVector`.
+
+.. code-block:: xml
+
+ <container-type name="std::vector" type="vector" opaque-containers="int:IntVector">
+ <include file-name="vector" 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>
+
+For the rest of the steps, we consider the three cases separately.
+
+**Case 1** - When a Python list is passed to a C++ function
+
+As the next step, we create a typesystem entry for the class `TestOpaqueContainer`.
+
+.. code-block:: xml
+
+ <value-type name="TestOpaqueContainer" />
+
+In this case, the typesystem entry is simple and the function
+`getVectorSum(const std::vector<int>&)` accepts `IntVector` as the parameter. This is
+because inherantly `IntVector` is the same as `std::vector<int>`.
+
+Now, build the code to create the \*_wrapper.cpp and \*.so files which we import into Python.
+
+Verifying the usage in Python
+
+.. code-block:: bash
+
+ >>> vector = IntVector()
+ >>> vector.push_back(2)
+ >>> vector.push_back(3)
+ >>> len(vector)
+ 2
+ >>> TestOpaqueContainer.getVectorSum(vector)
+ vector sum is 5
+
+**Case 2** - When the variable is public
+
+We create a typesystem entry for the class `TestOpaqueContainer`.
+
+.. code-block:: xml
+
+ <value-type name="TestOpaqueContainer">
+ <modify-field name="intVector" opaque-container="yes"/>
+ </value-type>
+
+In the `<modify-field />` notice the `opaque-container="yes"`. Since the type
+of `intVector' is `std::vector<int>`, it picks up the ``IntVector`` opaque
+container.
+
+Build the code to create the \*_wrapper.cpp and \*.so files which we import into Python.
+
+Verifying the usage in Python
+
+.. code-block:: bash
+
+ >>> test = TestOpaqueContainer()
+ >>> test
+ <Universe.TestOpaqueContainer object at 0x7fe17ef30c30>
+ >>> test.intVector.push_back(1)
+ >>> test.intVector.append(2)
+ >>> len(test.intVector)
+ 2
+ >>> test.intVector[1]
+ 2
+ >>> test.intVector.removeLast()
+ >>> len(test.intVector)
+ 1
+
+**Case 3** - When the variable is private and returned by reference through a getter
+
+Similar to the previous cases, we create a typesystem entry for the class `TestOpaqueContainer`.
+
+.. code-block:: xml
+
+ <value-type name="TestOpaqueContainer">
+ <modify-function signature="getIntVector()">
+ <modify-argument index="return">
+ <replace-type modified-type="IntVector" />
+ </modify-argument>
+ </modify-function>
+ </value-type>
+
+In this case, we specify the name of the opaque container `IntVector` in the <replace-type />
+field.
+
+Build the code to create the \*_wrapper.cpp and \*.so files which we import into Python.
+
+Verifying the usage in Python
+
+.. code-block:: bash
+
+ >>> test = TestOpaqueContainer()
+ >>> test
+ <Universe.TestOpaqueContainer object at 0x7f62b9094c30>
+ >>> vector = test.getIntVector()
+ >>> vector
+ <Universe.IntVector object at 0x7f62b91f7d00>
+ >>> vector.push_back(1)
+ >>> vector.push_back(2)
+ >>> len(vector)
+ 2
+ >>> vector[1]
+ 2
+ >>> vector.removeLast()
+ >>> len(vector)
+ 1
+
+In all the three cases, if we check out the corresponding wrapper class for the module, we will see
+the lines
+
+.. code-block:: c
+
+ static PyMethodDef IntVector_methods[] = {
+ {"push_back", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::push_back),METH_O, "push_back"},
+ {"append", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::push_back),METH_O, "append"},
+ {"clear", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::clear), METH_NOARGS, "clear"},
+ {"pop_back", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::pop_back), METH_NOARGS,
+ "pop_back"},
+ {"removeLast", reinterpret_cast<PyCFunction>(
+ ShibokenSequenceContainerPrivate<std::vector<int >>::pop_back), METH_NOARGS,
+ "removeLast"},
+ {nullptr, nullptr, 0, nullptr} // Sentinel
+ };
+
+This means, the above mentioned methods are available to be used in Python with the ``IntVector``
+opaque container.
+
+.. note:: `Plot example <https://doc.qt.io/qtforpython/examples/example_widgets_painting_plot.html>`_
+ demonstrates an example of using an opaque container `QPointList`, which wraps a C++
+ `QList<QPoint>`. The corresponding typesystem file where QPointList can be found `here
+ <https://code.qt.io/cgit/pyside/pyside-setup.git/tree/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml>`_
+