From 9599f4c02ec39ceb2513128fca02d148a5d00f32 Mon Sep 17 00:00:00 2001 From: Shyamnath Premnadh Date: Fri, 14 Jan 2022 12:33:07 +0100 Subject: Improve documentation - Opaque Containers The usage of opaque-containers through the 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 in C++, and use/modify this opaque container through Python. Task-number: PYSIDE-1776 Change-Id: Ieb86e38e2d666ea67194b129e16c5a9809ddb619 Reviewed-by: Christian Tismer --- sources/shiboken6/doc/typesystem_containers.rst | 203 ++++++++++++++++++++++++ 1 file changed, 203 insertions(+) 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`, 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&)` as an opaque container + +.. code-block:: c + + class TestOpaqueContainer + { + public: + static int getVectorSum(const std::vector& intVector) + { + return std::accumulate(intVector.begin(), intVector.end(), 0); + } + }; + +**Case 2** - When we have a C++ class named `TestOpaqueContainer` with a `std::vector` +public variable + +.. code-block:: c + + class TestOpaqueContainer + { + public: + std::vector intVector; + + }; + +**Case 3** - When we have a C++ class named `TestOpaqueContainer` with a `std::vector` as +private variable and the variable is returned by a reference through a getter. + +.. code-block:: c + + class TestOpaqueContainer + { + public: + std::vector& getIntVector() + { + return this->intVector; + } + + private: + std::vector 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 `` attribute in the typesystem +file, making Shiboken aware of the `IntVector`. + +.. code-block:: xml + + + + + + + + + + + + + + + +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 + + + +In this case, the typesystem entry is simple and the function +`getVectorSum(const std::vector&)` accepts `IntVector` as the parameter. This is +because inherantly `IntVector` is the same as `std::vector`. + +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 + + + + + +In the `` notice the `opaque-container="yes"`. Since the type +of `intVector' is `std::vector`, 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 + + >>> 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 + + + + + + + + + +In this case, we specify the name of the opaque container `IntVector` in the +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 + + >>> vector = test.getIntVector() + >>> vector + + >>> 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( + ShibokenSequenceContainerPrivate>::push_back),METH_O, "push_back"}, + {"append", reinterpret_cast( + ShibokenSequenceContainerPrivate>::push_back),METH_O, "append"}, + {"clear", reinterpret_cast( + ShibokenSequenceContainerPrivate>::clear), METH_NOARGS, "clear"}, + {"pop_back", reinterpret_cast( + ShibokenSequenceContainerPrivate>::pop_back), METH_NOARGS, + "pop_back"}, + {"removeLast", reinterpret_cast( + ShibokenSequenceContainerPrivate>::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 `_ + demonstrates an example of using an opaque container `QPointList`, which wraps a C++ + `QList`. The corresponding typesystem file where QPointList can be found `here + `_ + -- cgit v1.2.3