diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-01-10 15:14:13 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-01-11 15:28:28 +0100 |
commit | 4c2c58511df05febd7f51fe41c8e377435f9271e (patch) | |
tree | 046fc150014aad7f34372e18544d9a05bbcfbfea | |
parent | 2f0061786046f0855373eb4e099a8bfe0e7b7c2a (diff) |
shiboken6/libminimal: Add std::array (C++ 11)
[ChangeLog][shiboken6] Support for std::array has been added.
Task-number: PYSIDE-1605
Task-number: PYSIDE-2174
Change-Id: I5192dfe1fa88d794856169638bb97abfc916bcf5
Reviewed-by: Christian Tismer <tismer@stackless.com>
9 files changed, 102 insertions, 16 deletions
diff --git a/sources/shiboken6/ApiExtractor/predefined_templates.cpp b/sources/shiboken6/ApiExtractor/predefined_templates.cpp index 6e1459940..84c8fb5bc 100644 --- a/sources/shiboken6/ApiExtractor/predefined_templates.cpp +++ b/sources/shiboken6/ApiExtractor/predefined_templates.cpp @@ -39,6 +39,23 @@ while (true) { return result; } +// Convert a sequence to a limited/fixed array +static QString pySequenceToCppArray() +{ + return uR"(Shiboken::AutoDecRef it(PyObject_GetIter(%in)); +for (auto oit = std::begin(%out), oend = std::end(%out); oit != oend; ++oit) { + 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); + *oit = cppItem; +} +)"_s; +} + static const char stlMapKeyAccessor[] = "->first"; static const char stlMapValueAccessor[] = "->second"; static const char qtMapKeyAccessor[] = ".key()"; @@ -192,6 +209,8 @@ return %out;)"_s}, pySequenceToCppContainer(u"push_back"_s, false)}, {u"shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve"_s, pySequenceToCppContainer(u"push_back"_s, true)}, + {u"shiboken_conversion_pyiterable_to_cpparray"_s, + pySequenceToCppArray()}, {u"shiboken_conversion_pyiterable_to_cppsetcontainer"_s, pySequenceToCppContainer(u"insert"_s, false)}, diff --git a/sources/shiboken6/ApiExtractor/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp index 1b2d7e7b7..240ad0df8 100644 --- a/sources/shiboken6/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp @@ -856,6 +856,7 @@ void TypeDatabasePrivate::addBuiltInContainerTypes(const TypeDatabaseParserConte { // Unless the user has added the standard containers (potentially with // some opaque types), add them by default. + const bool hasStdArray = findType(u"std::array"_s) != nullptr; const bool hasStdPair = findType(u"std::pair"_s) != nullptr; const bool hasStdList = findType(u"std::list"_s) != nullptr; const bool hasStdVector = findType(u"std::vector"_s) != nullptr; @@ -866,6 +867,13 @@ void TypeDatabasePrivate::addBuiltInContainerTypes(const TypeDatabaseParserConte return; QByteArray ts = R"(<?xml version="1.0" encoding="UTF-8"?><typesystem>)"; + if (!hasStdArray) { + ts += containerTypeSystemSnippet( + "std::array", "list", "array", + "shiboken_conversion_cppsequence_to_pylist", + "PySequence", + "shiboken_conversion_pyiterable_to_cpparray"); + } if (!hasStdPair) { ts += containerTypeSystemSnippet( "std::pair", "pair", "utility", diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index 52b0ee4df..dca076c1a 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -541,8 +541,15 @@ container-type are equivalent to *map* and *multi-map*, respectively. The *optional* **opaque-containers** attribute specifies a semi-colon separated - list of colon separated pairs of instantiation and name for - :ref:`opaque-containers`. + list of mappings from instantiations to a type name for + :ref:`opaque-containers`: + + .. code-block:: xml + + <typesystem> + <container-type name="std::array" + opaque-containers ="int,3:IntArray3;float,4:FloatArray4"> + The *optional* **since** value is used to specify the API version of this container. diff --git a/sources/shiboken6/doc/typesystem_templates.rst b/sources/shiboken6/doc/typesystem_templates.rst index abb7ab3f2..bf9598db1 100644 --- a/sources/shiboken6/doc/typesystem_templates.rst +++ b/sources/shiboken6/doc/typesystem_templates.rst @@ -89,6 +89,8 @@ In case they need to explicitly specified, the following templates can be used: +----------------------------------------------------------------------+------------------------------------------------------------------------------------+ | ``shiboken_conversion_pyiterable_to_cppsequentialcontainer_reserve`` | Convert an iterable Python type to a C++ sequential container supporting reserve() | +----------------------------------------------------------------------+------------------------------------------------------------------------------------+ + | ``shiboken_conversion_pyiterable_to_cpparray`` | Convert an iterable Python type to a fixed-size array (std::array, std::span) | + +----------------------------------------------------------------------+------------------------------------------------------------------------------------+ | ``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 | diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp index 5c691df6f..360ae703d 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator_container.cpp @@ -151,22 +151,26 @@ CppGenerator::OpaqueContainerData + cppSignature + u'>'; // methods - const bool isStdVector = containerType.name() == u"std::vector"; + const QString &containerName = containerType.name(); + const bool isStdVector = containerName == u"std::vector"; + const bool isFixed = containerName == u"std::array"; const QString methods = result.name + u"_methods"_s; s << "static PyMethodDef " << methods << "[] = {\n" << indent; - writeMethod(s, privateObjType, "push_back"); - writeMethod(s, privateObjType, "push_back", "append"); // Qt convention - writeNoArgsMethod(s, privateObjType, "clear"); - writeNoArgsMethod(s, privateObjType, "pop_back"); - writeNoArgsMethod(s, privateObjType, "pop_back", "removeLast"); // Qt convention - if (!isStdVector) { - writeMethod(s, privateObjType, "push_front"); - writeMethod(s, privateObjType, "push_front", "prepend"); // Qt convention - writeNoArgsMethod(s, privateObjType, "pop_front"); - writeMethod(s, privateObjType, "pop_front", "removeFirst"); // Qt convention + if (!isFixed) { + writeMethod(s, privateObjType, "push_back"); + writeMethod(s, privateObjType, "push_back", "append"); // Qt convention + writeNoArgsMethod(s, privateObjType, "clear"); + writeNoArgsMethod(s, privateObjType, "pop_back"); + writeNoArgsMethod(s, privateObjType, "pop_back", "removeLast"); // Qt convention + if (!isStdVector) { + writeMethod(s, privateObjType, "push_front"); + writeMethod(s, privateObjType, "push_front", "prepend"); // Qt convention + writeNoArgsMethod(s, privateObjType, "pop_front"); + writeMethod(s, privateObjType, "pop_front", "removeFirst"); // Qt convention + } + writeMethod(s, privateObjType, "reserve"); // SFINAE'd out for list + writeNoArgsMethod(s, privateObjType, "capacity"); } - writeMethod(s, privateObjType, "reserve"); - writeNoArgsMethod(s, privateObjType, "capacity"); writeNoArgsMethod(s, privateObjType, "data"); writeNoArgsMethod(s, privateObjType, "constData"); s << "{nullptr, nullptr, 0, nullptr} // Sentinel\n" diff --git a/sources/shiboken6/tests/libminimal/containeruser.cpp b/sources/shiboken6/tests/libminimal/containeruser.cpp index 78fc7a045..29af52aef 100644 --- a/sources/shiboken6/tests/libminimal/containeruser.cpp +++ b/sources/shiboken6/tests/libminimal/containeruser.cpp @@ -6,7 +6,7 @@ #include <algorithm> #include <numeric> -ContainerUser::ContainerUser() : m_intVector{1, 2, 3} +ContainerUser::ContainerUser() : m_intVector{1, 2, 3}, m_intArray{1, 2, 3} { } @@ -33,3 +33,23 @@ void ContainerUser::setIntVector(const std::vector<int> &v) { m_intVector = v; } + +std::array<int, 3> ContainerUser::createIntArray() +{ + return {1, 2, 3}; +} + +int ContainerUser::sumIntArray(const std::array<int, 3> &intArray) +{ + return std::accumulate(intArray.cbegin(), intArray.cend(), 0); +} + +std::array<int, 3> &ContainerUser::intArray() +{ + return m_intArray; +} + +void ContainerUser::setIntArray(const std::array<int, 3> &a) +{ + m_intArray = a; +} diff --git a/sources/shiboken6/tests/libminimal/containeruser.h b/sources/shiboken6/tests/libminimal/containeruser.h index 4cb4df0b9..55e4020ec 100644 --- a/sources/shiboken6/tests/libminimal/containeruser.h +++ b/sources/shiboken6/tests/libminimal/containeruser.h @@ -6,6 +6,7 @@ #include "libminimalmacros.h" +#include <array> #include <vector> /// Exercise simple, sequential containers. More advanced tests are in ListUser @@ -21,8 +22,15 @@ public: std::vector<int> &intVector(); void setIntVector(const std::vector<int> &); + static std::array<int, 3> createIntArray(); + static int sumIntArray(const std::array<int, 3> &intArray); + + std::array<int, 3> &intArray(); + void setIntArray(const std::array<int, 3> &); + private: std::vector<int> m_intVector; + std::array<int, 3> m_intArray; }; #endif // CONTAINERUSER_H diff --git a/sources/shiboken6/tests/minimalbinding/containeruser_test.py b/sources/shiboken6/tests/minimalbinding/containeruser_test.py index b08989d2f..25d683957 100644 --- a/sources/shiboken6/tests/minimalbinding/containeruser_test.py +++ b/sources/shiboken6/tests/minimalbinding/containeruser_test.py @@ -28,6 +28,17 @@ class ContainerTest(unittest.TestCase): oc[0] = 42 self.assertEqual(cu.intVector()[0], 42) + def testArrayConversion(self): + v = ContainerUser.createIntArray() + self.assertEqual(ContainerUser.sumIntArray(v), 6) + + def testArrayOpaqueContainer(self): + cu = ContainerUser() + oc = cu.intArray() + self.assertEqual(oc[0], 1) + oc[0] = 42 + self.assertEqual(cu.intArray()[0], 42) + if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml index 1b16e0709..e73ddc228 100644 --- a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml +++ b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml @@ -19,6 +19,8 @@ <opaque-container name="std::vector" opaque-containers="int:StdIntVector"/> + <opaque-container name="std::array" opaque-containers="int,3:StdIntArray"/> + <object-type name="Obj"/> <value-type name="Val"> <enum-type name="ValEnum"/> @@ -44,6 +46,11 @@ <replace-type modified-type="StdIntVector"/> </modify-argument> </modify-function> + <modify-function signature="intArray()"> + <modify-argument index="return"> + <replace-type modified-type="StdIntArray"/> + </modify-argument> + </modify-function> </value-type> <!-- Test wrapping of a typedef --> |