aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken/sbkconverter_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken/sbkconverter_p.h')
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter_p.h536
1 files changed, 536 insertions, 0 deletions
diff --git a/sources/shiboken6/libshiboken/sbkconverter_p.h b/sources/shiboken6/libshiboken/sbkconverter_p.h
new file mode 100644
index 000000000..c886c9b9f
--- /dev/null
+++ b/sources/shiboken6/libshiboken/sbkconverter_p.h
@@ -0,0 +1,536 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SBK_CONVERTER_P_H
+#define SBK_CONVERTER_P_H
+
+#include "sbkpython.h"
+#include "sbkconverter.h"
+#include "sbkcppstring.h"
+#include "sbkstring.h"
+#include <limits>
+#include <typeinfo>
+#include <sstream>
+#include <iostream>
+#include <vector>
+
+extern "C"
+{
+
+using ToCppConversion = std::pair<IsConvertibleToCppFunc, PythonToCppFunc>;
+using ToCppConversionVector = std::vector<ToCppConversion>;
+
+/**
+ * \internal
+ * Private structure of SbkConverter.
+ */
+struct SbkConverter
+{
+ /**
+ * Python type associated with this converter. If the type is a Shiboken
+ * wrapper, then it must be a SbkObjectType; otherwise it will be the
+ * Python type to which the C++ value will be converted (note that the
+ * C++ type could be produced from various Python types).
+ */
+ PyTypeObject *pythonType;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the C++ object is kept,
+ * because it looks for an already existing Python wrapper associated
+ * with the C++ instance.
+ * It is used to convert C++ pointers and references to Python objects.
+ */
+ CppToPythonFunc pointerToPython;
+ /**
+ * This function converts a C++ object to a Python object of the type
+ * indicated in pythonType. The identity of the object is not kept,
+ * because a new instance of the C++ object is created.
+ * It is used to convert objects passed by value, or reference, if said
+ * reference can't be traced to an object that already has a Python
+ * wrapper assigned for it.
+ */
+ CppToPythonFunc copyToPython;
+ /**
+ * This is a special case of a Python to C++ conversion. It returns
+ * the underlying C++ pointer of a Python wrapper passed as parameter
+ * or NULL if the Python object is a None value.
+ * It comes separated from the other toCppConversions because if you
+ * have a Python object representing a Value Type the type checking
+ * for both ValueType and ValueType *would be the same, thus the first
+ * check would be true and the second would never be reached.
+ */
+ ToCppConversion toCppPointerConversion;
+ /**
+ * This is a list of type checking functions that return the
+ * proper Python to C++ conversion function, for the given Python
+ * object.
+ * For Object Types, that never have implicit conversions, this
+ * list is always empty.
+ */
+ ToCppConversionVector toCppConversions;
+};
+
+} // extern "C"
+
+template<typename T, typename MaxLimitType, bool isSigned>
+struct OverFlowCheckerBase {
+ static void formatOverFlowMessage(const MaxLimitType &value,
+ const std::string *valueAsString = nullptr)
+ {
+ std::ostringstream str;
+ str << "libshiboken: Overflow: Value ";
+ if (valueAsString != nullptr && !valueAsString->empty())
+ str << *valueAsString;
+ else
+ str << value;
+ str << " exceeds limits of type "
+ << " [" << (isSigned ? "signed" : "unsigned")
+ << "] \"" << typeid(T).name()
+ << "\" (" << sizeof(T) << "bytes).";
+ const std::string message = str.str();
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0);
+ }
+
+ // Checks if an overflow occurred inside Python code.
+ // Precondition: use after calls like PyLong_AsLongLong or PyLong_AsUnsignedLongLong.
+ // Postcondition: if error ocurred, sets the string reference to the string representation of
+ // the passed value.
+ static bool checkForInternalPyOverflow(PyObject *pyIn, std::string &valueAsString)
+ {
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyObject *stringRepresentation = PyObject_Str(pyIn);
+ const char *cString = Shiboken::String::toCString(stringRepresentation);
+ valueAsString.assign(cString);
+ Py_DECREF(stringRepresentation);
+ return true;
+ }
+ return false;
+ }
+};
+
+// Helper template for checking if a value overflows when cast to type T.
+// The MaxLimitType size is usually >= than type T size, so that it can still represent values that
+// can't be stored in T (unless the types are of course the same).
+// TLDR: MaxLimitType is either long long or unsigned long long.
+template<typename T, typename MaxLimitType = PY_LONG_LONG,
+ bool isSigned = std::numeric_limits<T>::is_signed >
+struct OverFlowChecker;
+
+template<typename T, typename MaxLimitType>
+struct OverFlowChecker<T, MaxLimitType, true> :
+ public OverFlowCheckerBase<T, MaxLimitType, true> {
+ static bool check(const MaxLimitType &value, PyObject *pyIn)
+ {
+ std::string valueAsString;
+ const bool isOverflow =
+ OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString)
+ || value < std::numeric_limits<T>::min()
+ || value > std::numeric_limits<T>::max();
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+ }
+};
+
+template<typename T, typename MaxLimitType>
+struct OverFlowChecker<T, MaxLimitType, false>
+ : public OverFlowCheckerBase<T, MaxLimitType, false> {
+ static bool check(const MaxLimitType &value, PyObject *pyIn)
+ {
+ std::string valueAsString;
+ const bool isOverflow =
+ OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString)
+ || value < 0
+ || static_cast<unsigned long long>(value) > std::numeric_limits<T>::max();
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+ }
+};
+template<>
+struct OverFlowChecker<PY_LONG_LONG, PY_LONG_LONG, true> :
+ public OverFlowCheckerBase<PY_LONG_LONG, PY_LONG_LONG, true> {
+ static bool check(const PY_LONG_LONG &value, PyObject *pyIn) {
+ std::string valueAsString;
+ const bool isOverflow = checkForInternalPyOverflow(pyIn, valueAsString);
+ if (isOverflow)
+ OverFlowChecker::formatOverFlowMessage(value, &valueAsString);
+ return isOverflow;
+
+ }
+};
+template<>
+struct OverFlowChecker<double, PY_LONG_LONG, true> {
+ static bool check(const double &, PyObject *) { return false; }
+};
+template<>
+struct OverFlowChecker<float, PY_LONG_LONG, true> :
+ public OverFlowCheckerBase<float, PY_LONG_LONG, true> {
+ static bool check(const double &value, PyObject *)
+ {
+ const bool result = value < std::numeric_limits<float>::min()
+ || value > std::numeric_limits<float>::max();
+ if (result)
+ formatOverFlowMessage(value);
+ return result;
+ }
+};
+
+// Basic primitive type converters ---------------------------------------------------------
+
+template <typename T> struct Primitive {};
+
+template <typename T>
+struct OnePrimitive
+{
+ static PyObject *toPython(const void *) { return nullptr; }
+ static PythonToCppFunc isConvertible(PyObject *) { return nullptr; }
+ static void toCpp(PyObject *, void *) {}
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = Shiboken::Conversions::createConverter(Shiboken::SbkType<T>(),
+ Primitive<T>::toPython);
+ Shiboken::Conversions::addPythonToCppValueConversion(converter,
+ Primitive<T>::toCpp,
+ Primitive<T>::isConvertible);
+ return converter;
+ }
+};
+template <typename T>
+struct TwoPrimitive : OnePrimitive<T>
+{
+ static PythonToCppFunc isOtherConvertible(PyObject *) { return nullptr; }
+ static void otherToCpp(PyObject *, void *) {}
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = OnePrimitive<T>::createConverter();
+ Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive<T>::otherToCpp, Primitive<T>::isOtherConvertible);
+ return converter;
+ }
+};
+
+// Integers --------------------------------------------------------------------------------
+
+template <typename INT>
+struct IntPrimitive : TwoPrimitive<INT>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromLong(*reinterpret_cast<const INT *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ double result = PyFloat_AS_DOUBLE(pyIn);
+ // If cast to long directly it could overflow silently.
+ if (OverFlowChecker<INT>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<INT * >(cppOut) = static_cast<INT>(result);
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyFloat_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<INT>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<INT * >(cppOut) = static_cast<INT>(result);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+template <> struct Primitive<int> : IntPrimitive<int> {};
+template <> struct Primitive<long> : IntPrimitive<long> {};
+template <> struct Primitive<short> : IntPrimitive<short> {};
+template <> struct Primitive<unsigned short> : IntPrimitive<unsigned short> {};
+
+// Unsigned Long Integers ------------------------------------------------------------------
+
+template <typename LONG>
+struct UnsignedLongPrimitive : IntPrimitive<LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromUnsignedLong(*reinterpret_cast<const LONG *>(cppIn));
+ }
+};
+template <> struct Primitive<unsigned int> : UnsignedLongPrimitive<unsigned int> {};
+template <> struct Primitive<unsigned long> : UnsignedLongPrimitive<unsigned long> {};
+
+// Big integers ----------------------------------------------------------------------------
+
+template <>
+struct Primitive<PY_LONG_LONG> : OnePrimitive<PY_LONG_LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromLongLong(*reinterpret_cast<const PY_LONG_LONG *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<PY_LONG_LONG>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<PY_LONG_LONG * >(cppOut) = result;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<unsigned PY_LONG_LONG> : OnePrimitive<unsigned PY_LONG_LONG>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyLong_FromUnsignedLongLong(*static_cast<const unsigned PY_LONG_LONG *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ if (PyLong_Check(pyIn)) {
+ unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn);
+ if (OverFlowChecker<unsigned PY_LONG_LONG, unsigned PY_LONG_LONG>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<unsigned PY_LONG_LONG * >(cppOut) = result;
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion");
+ }
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+};
+
+// Floating point --------------------------------------------------------------------------
+
+template <typename FLOAT>
+struct FloatPrimitive : TwoPrimitive<FLOAT>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyFloat_FromDouble(*reinterpret_cast<const FLOAT *>(cppIn));
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyLong_AsDouble(pyIn));
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyLong_Check(pyIn) || PyLong_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<FLOAT *>(cppOut) = FLOAT(PyFloat_AsDouble(pyIn));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+template <> struct Primitive<float> : FloatPrimitive<float> {};
+template <> struct Primitive<double> : FloatPrimitive<double> {};
+
+// Boolean ---------------------------------------------------------------------------------
+
+template <>
+struct Primitive<bool> : OnePrimitive<bool>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return PyBool_FromLong(*reinterpret_cast<const bool *>(cppIn));
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<bool *>(cppOut) = PyLong_AS_LONG(pyIn) != 0;
+ }
+};
+
+// Characters ------------------------------------------------------------------------------
+
+template <typename CHAR>
+struct CharPrimitive : IntPrimitive<CHAR>
+{
+ static void toCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<CHAR *>(cppOut) = CHAR(Shiboken::String::toCString(pyIn)[0]);
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::checkChar(pyIn))
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ PY_LONG_LONG result = PyLong_AsLongLong(pyIn);
+ if (OverFlowChecker<CHAR>::check(result, pyIn))
+ PyErr_SetObject(PyExc_OverflowError, nullptr);
+ *reinterpret_cast<CHAR *>(cppOut) = CHAR(result);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (PyNumber_Check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+ static SbkConverter *createConverter()
+ {
+ SbkConverter *converter = IntPrimitive<CHAR>::createConverter();
+ Shiboken::Conversions::addPythonToCppValueConversion(converter, CharPrimitive<CHAR>::otherToCpp, CharPrimitive<CHAR>::isOtherConvertible);
+ return converter;
+ }
+
+};
+template <> struct Primitive<signed char> : CharPrimitive<signed char> {};
+template <> struct Primitive<unsigned char> : CharPrimitive<unsigned char> {};
+template <> struct Primitive<char> : CharPrimitive<char> {
+ using CharPrimitive<char>::toPython;
+ static PyObject *toPython(const void *cppIn) {
+ return Shiboken::String::fromCString(reinterpret_cast<const char *>(cppIn), 1);
+ }
+};
+
+
+
+// Strings ---------------------------------------------------------------------------------
+
+template <>
+struct Primitive<const char *> : TwoPrimitive<const char *>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ if (!cppIn)
+ Py_RETURN_NONE;
+ return Shiboken::String::fromCString(reinterpret_cast<const char *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<const char **>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ *reinterpret_cast<const char **>(cppOut) = Shiboken::String::toCString(pyIn);
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<std::string> : TwoPrimitive<std::string>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return Shiboken::String::fromCppString(*reinterpret_cast<const std::string *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ reinterpret_cast<std::string *>(cppOut)->clear();
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ Shiboken::String::toCppString(pyIn, reinterpret_cast<std::string *>(cppOut));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ if (Shiboken::String::check(pyIn))
+ return otherToCpp;
+ return nullptr;
+ }
+};
+
+template <>
+struct Primitive<std::wstring> : TwoPrimitive<std::wstring>
+{
+ static PyObject *toPython(const void *cppIn)
+ {
+ return Shiboken::String::fromCppWString(*reinterpret_cast<const std::wstring *>(cppIn));
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ reinterpret_cast<std::wstring *>(cppOut)->clear();
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ return pyIn == Py_None ? toCpp : nullptr;
+ }
+ static void otherToCpp(PyObject *pyIn, void *cppOut)
+ {
+ Shiboken::String::toCppWString(pyIn, reinterpret_cast<std::wstring *>(cppOut));
+ }
+ static PythonToCppFunc isOtherConvertible(PyObject *pyIn)
+ {
+ return PyUnicode_Check(pyIn) ? otherToCpp : nullptr;
+ }
+};
+
+// nullptr_t
+template <>
+struct Primitive<std::nullptr_t> : OnePrimitive<std::nullptr_t>
+{
+ static PyObject *toPython(const void * /* cppIn */)
+ {
+ Py_RETURN_NONE;
+ }
+ static void toCpp(PyObject *, void *cppOut)
+ {
+ *reinterpret_cast<std::nullptr_t *>(cppOut) = nullptr;
+ }
+ static PythonToCppFunc isConvertible(PyObject *pyIn)
+ {
+ if (pyIn == Py_None)
+ return toCpp;
+ return nullptr;
+ }
+};
+
+namespace Shiboken::Conversions {
+
+SbkConverter *createConverterObject(PyTypeObject *type,
+ PythonToCppFunc toCppPointerConvFunc,
+ IsConvertibleToCppFunc toCppPointerCheckFunc,
+ CppToPythonFunc pointerToPythonFunc,
+ CppToPythonFunc copyToPythonFunc);
+} // namespace Shiboken::Conversions
+
+#endif // SBK_CONVERTER_P_H