diff --git a/src/PythonQt.cpp b/src/PythonQt.cpp index 95dc1c58d..6932afa43 100644 --- a/src/PythonQt.cpp +++ b/src/PythonQt.cpp @@ -391,11 +391,9 @@ PythonQtPrivate::~PythonQtPrivate() { delete i.next().value(); } } - PythonQtConv::global_valueStorage.clear(); - PythonQtConv::global_ptrStorage.clear(); - PythonQtConv::global_variantStorage.clear(); PythonQtMethodInfo::cleanupCachedMethodInfos(); + PythonQtArgumentFrame::cleanupFreeList(); } void PythonQt::setRedirectStdInCallback(PythonQtInputChangedCB* callback, void * callbackData) diff --git a/src/PythonQtConversion.cpp b/src/PythonQtConversion.cpp index 22408d022..523b3fec5 100644 --- a/src/PythonQtConversion.cpp +++ b/src/PythonQtConversion.cpp @@ -48,10 +48,6 @@ #include #include -PythonQtValueStorage PythonQtConv::global_valueStorage; -PythonQtValueStorage PythonQtConv::global_ptrStorage; -PythonQtValueStorageWithCleanup PythonQtConv::global_variantStorage; - QHash PythonQtConv::_metaTypeToPythonConverters; QHash PythonQtConv::_pythonToMetaTypeConverters; @@ -224,15 +220,15 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat return Py_None; } - void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info) { + void* PythonQtConv::CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info, PythonQtArgumentFrame* frame) { void* ptr = NULL; if (info.pointerCount>1) { return NULL; } else if (info.pointerCount==1) { - PythonQtValueStorage_ADD_VALUE(global_ptrStorage, void*, NULL, ptr); + PythonQtArgumentFrame_ADD_VALUE(frame, void*, NULL, ptr); } else if (info.enumWrapper) { // create enum return value - PythonQtValueStorage_ADD_VALUE(PythonQtConv::global_valueStorage, long, 0, ptr); + PythonQtArgumentFrame_ADD_VALUE(frame, long, 0, ptr); } else { switch (info.typeId) { case QMetaType::Char: @@ -249,24 +245,24 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat case QMetaType::Double: case QMetaType::LongLong: case QMetaType::ULongLong: - PythonQtValueStorage_ADD_VALUE(global_valueStorage, qint64, 0, ptr); + PythonQtArgumentFrame_ADD_VALUE(frame, qint64, 0, ptr); break; case PythonQtMethodInfo::Variant: - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, 0, ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, 0, ptr); // return the ptr to the variant break; default: // check if we have a QList of pointers, which we can circumvent with a QList if (info.isQList && (info.innerNamePointerCount == 1)) { static int id = QMetaType::type("QList"); - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QVariant::Type(id), ptr); // return the constData pointer that will be filled with the result value later on ptr = (void*)((QVariant*)ptr)->constData(); } if (!ptr && info.typeId != PythonQtMethodInfo::Unknown) { // everything else is stored in a QVariant, if we know the meta type... - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QVariant::Type(info.typeId), ptr); // return the constData pointer that will be filled with the result value later on ptr = (void*)((QVariant*)ptr)->constData(); } @@ -295,7 +291,7 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat return object; } -void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject) +void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame) { void* ptr = alreadyAllocatedCPPObject; @@ -309,7 +305,7 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo if ((PyObject*)obj->ob_type == qtCursorShapeEnum) { Qt::CursorShape val = (Qt::CursorShape)PyInt_AsLong(obj); if (!ptr) { - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QCursor(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QCursor(), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } *((QCursor*)ptr) = QCursor(val); @@ -321,14 +317,14 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo if ((PyObject*)obj->ob_type == qtGlobalColorEnum) { Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AsLong(obj); if (!ptr) { - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QPen(), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } *((QPen*)ptr) = QPen(QColor(val)); return ptr; } else if ((PyObject*)obj->ob_type == qtColorClass) { if (!ptr) { - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QPen(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QPen(), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } *((QPen*)ptr) = QPen(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr)); @@ -340,14 +336,14 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo if ((PyObject*)obj->ob_type == qtGlobalColorEnum) { Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AsLong(obj); if (!ptr) { - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QBrush(), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } *((QBrush*)ptr) = QBrush(QColor(val)); return ptr; } else if ((PyObject*)obj->ob_type == qtColorClass) { if (!ptr) { - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QBrush(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QBrush(), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } *((QBrush*)ptr) = QBrush(*((QColor*)((PythonQtInstanceWrapper*)obj)->_wrappedPtr)); @@ -358,7 +354,7 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo if ((PyObject*)obj->ob_type == qtGlobalColorEnum) { Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AsLong(obj); if (!ptr) { - PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QColor(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE(frame, QColor(), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } *((QColor*)ptr) = QColor(val); @@ -368,14 +364,14 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo return NULL; } -void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject) +void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* /*classInfo*/, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame) { bool ok = false; void* ptr = NULL; // autoconversion of QPen/QBrush/QCursor/QColor from different type if (info.pointerCount==0 && !strict) { - ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject); + ptr = handlePythonToQtAutoConversion(info.typeId, obj, alreadyAllocatedCPPObject, frame); if (ptr) { return ptr; } @@ -383,7 +379,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (info.pointerCount==1 && PythonQtBoolResult_Check(obj) && info.typeId == QMetaType::Bool) { PythonQtBoolResultObject* boolResul = (PythonQtBoolResultObject*)obj; // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, &boolResul->_value, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, void*, &boolResul->_value, ptr); return ptr; } @@ -406,7 +402,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i } if (info.pointerCount==1) { // store the wrapped pointer in an extra pointer and let ptr point to the extra pointer - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, object, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, void*, object, ptr); } else if (info.pointerCount==0) { // store the wrapped pointer directly, since we are a reference ptr = object; @@ -415,7 +411,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // not matching, maybe a PyObject*? if (info.name == "PyObject" && info.pointerCount==1) { // handle low level PyObject directly - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, obj, ptr); } } } else if (info.pointerCount == 1) { @@ -425,7 +421,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (obj->ob_type == &PyBytes_Type) { // take direct reference to string data const char* data = PyBytes_AS_STRING(obj); - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (void*)data, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, (void*)data, ptr); } else { // convert to string QString str = PyObjGetString(obj, strict, ok); @@ -434,8 +430,8 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i bytes = str.toUtf8(); if (ok) { void* ptr2 = NULL; - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(bytes), ptr2); - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(NULL,frame, QVariant(bytes), ptr2); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, void*, (((QByteArray*)((QVariant*)ptr2)->constData())->data()), ptr); } } } @@ -446,26 +442,26 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i QString str = PyObjGetString(obj, strict, ok); if (ok) { void* ptr2 = NULL; - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(NULL,global_variantStorage, QVariant, QVariant(str), ptr2); - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, (void*)((QVariant*)ptr2)->constData(), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(NULL,frame, QVariant(str), ptr2); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, void*, (void*)((QVariant*)ptr2)->constData(), ptr); } } else if (info.name == "PyObject") { // handle low level PyObject directly - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, obj, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, obj, ptr); } else if (obj == Py_None) { // None is treated as a NULL ptr - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, NULL, ptr); } else { void* foreignWrapper = PythonQt::priv()->unwrapForeignWrapper(info.name, obj); if (foreignWrapper) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, foreignWrapper, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, foreignWrapper, ptr); } else { // if we are not strict, we try if we are passed a 0 integer if (!strict) { bool ok; int value = PyObjGetInt(obj, true, ok); if (ok && value==0) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_ptrStorage, void*, NULL, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, void*, NULL, ptr); } } } @@ -477,7 +473,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { int val = PyObjGetInt(obj, strict, ok); if (ok && (val >= CHAR_MIN && val <= CHAR_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, char, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, char, val, ptr); } } break; @@ -485,7 +481,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { int val = PyObjGetInt(obj, strict, ok); if (ok && (val >= 0 && val <= UCHAR_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned char, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned char, val, ptr); } } break; @@ -493,7 +489,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { int val = PyObjGetInt(obj, strict, ok); if (ok && (val >= SHRT_MIN && val <= SHRT_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, short, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, short, val, ptr); } } break; @@ -501,7 +497,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { int val = PyObjGetInt(obj, strict, ok); if (ok && (val >= 0 && val <= USHRT_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned short, val, ptr); } } break; @@ -509,7 +505,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { qint64 val = PyObjGetLongLong(obj, strict, ok); if (ok && (val >= LONG_MIN && val <= LONG_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, long, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, long, val, ptr); } } break; @@ -517,7 +513,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { qint64 val = (unsigned long)PyObjGetLongLong(obj, strict, ok); if (ok && (val >= 0 && val <= ULONG_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned long, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned long, val, ptr); } } break; @@ -525,7 +521,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { bool val = PyObjGetBool(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, bool, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, bool, val, ptr); } } break; @@ -533,7 +529,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { qint64 val = PyObjGetLongLong(obj, strict, ok); if (ok && (val >= INT_MIN && val <= INT_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, int, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, int, val, ptr); } } break; @@ -541,7 +537,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { quint64 val = PyObjGetLongLong(obj, strict, ok); if (ok && (val >= 0 && val <= UINT_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned int, val, ptr); } } break; @@ -549,7 +545,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { int val = PyObjGetInt(obj, strict, ok); if (ok && (val >= 0 && val <= USHRT_MAX)) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned short, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, unsigned short, val, ptr); } } break; @@ -557,7 +553,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { float val = (float)PyObjGetDouble(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, float, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, float, val, ptr); } } break; @@ -565,7 +561,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { double val = PyObjGetDouble(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, double, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, double, val, ptr); } } break; @@ -573,7 +569,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { qint64 val = PyObjGetLongLong(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, qint64, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, qint64, val, ptr); } } break; @@ -581,7 +577,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { quint64 val = PyObjGetULongLong(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, quint64, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, quint64, val, ptr); } } break; @@ -595,7 +591,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i bytes = PyObjGetString(obj, true, ok).toUtf8(); } if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(bytes), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, QVariant(bytes), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } } @@ -604,7 +600,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { QString str = PyObjGetString(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(str), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant(str), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } } @@ -613,7 +609,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i { QStringList l = PyObjToStringList(obj, strict, ok); if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant(l), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, QVariant(l), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } } @@ -624,7 +620,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i QVariant v = PyObjToQVariant(obj); // the only case where conversion can fail it None and we want to pass that to, e.g. setProperty(), // so we do not check v.isValid() here - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, v, ptr); } break; default: @@ -643,7 +639,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i val = (unsigned int)PyObjGetLongLong(obj, false, ok); } if (ok) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_valueStorage, unsigned int, val, ptr); + PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, unsigned int, val, ptr); return ptr; } else { return NULL; @@ -655,7 +651,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (info.isQList && (info.innerNamePointerCount == 1)) { static int id = QMetaType::type("QList"); if (!alreadyAllocatedCPPObject) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, global_variantStorage, QVariant, QVariant::Type(id), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, frame, QVariant::Type(id), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } else { ptr = alreadyAllocatedCPPObject; @@ -676,7 +672,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i if (converter) { if (!alreadyAllocatedCPPObject) { // create a new empty variant of concrete type: - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, QVariant::Type(info.typeId), ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, QVariant::Type(info.typeId), ptr); ptr = (void*)((QVariant*)ptr)->constData(); } else { ptr = alreadyAllocatedCPPObject; @@ -695,7 +691,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i // for all other types, we use the same qvariant conversion and pass out the constData of the variant: QVariant v = PyObjToQVariant(obj, info.typeId); if (v.isValid()) { - PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,global_variantStorage, QVariant, v, ptr); + PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedCPPObject,frame, v, ptr); ptr = (void*)((QVariant*)ptr)->constData(); } } diff --git a/src/PythonQtConversion.h b/src/PythonQtConversion.h index 5c31fd26b..9cf997558 100644 --- a/src/PythonQtConversion.h +++ b/src/PythonQtConversion.h @@ -109,10 +109,10 @@ class PYTHONQT_EXPORT PythonQtConv { static PyObject* ConvertQtValueToPython(const PythonQtMethodInfo::ParameterInfo& info, const void* data); //! convert python object to Qt (according to the given parameter) and if the conversion should be strict (classInfo is currently not used anymore) - static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject = NULL); + static void* ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& info, PyObject* obj, bool strict, PythonQtClassInfo* classInfo, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame = NULL); //! creates a data storage for the passed parameter type and returns a void pointer to be set as arg[0] of qt_metacall - static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info); + static void* CreateQtReturnValue(const PythonQtMethodInfo::ParameterInfo& info, PythonQtArgumentFrame* frame); //! converts QString to Python string (unicode!) static PyObject* QStringToPyObject(const QString& str); @@ -193,19 +193,13 @@ class PYTHONQT_EXPORT PythonQtConv { //! Returns if the given object is a string (or unicode string) static bool isStringType(PyTypeObject* type); -public: - - static PythonQtValueStorage global_valueStorage; - static PythonQtValueStorage global_ptrStorage; - static PythonQtValueStorageWithCleanup global_variantStorage; - protected: static QHash _metaTypeToPythonConverters; static QHash _pythonToMetaTypeConverters; static PythonQtConvertPythonSequenceToQVariantListCB* _pythonSequenceToQVariantListCB; //! handle automatic conversion of some special types (QColor, QBrush, ...) - static void* handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject); + static void* handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject, PythonQtArgumentFrame* frame); //! converts the list of pointers of given type to Python static PyObject* ConvertQListOfPointerTypeToPythonList(QList* list, const PythonQtMethodInfo::ParameterInfo& info); diff --git a/src/PythonQtMisc.cpp b/src/PythonQtMisc.cpp index 672ad0880..3575156df 100644 --- a/src/PythonQtMisc.cpp +++ b/src/PythonQtMisc.cpp @@ -40,4 +40,78 @@ //---------------------------------------------------------------------------------- #include "PythonQtMisc.h" +#include +#define PYTHONQT_MAX_ARGUMENT_FRAME_SIZE (PYTHONQT_MAX_ARGS * 2) + +PythonQtArgumentFrame* PythonQtArgumentFrame::_freeListHead = NULL; + +PythonQtArgumentFrame::PythonQtArgumentFrame() +{ + _freeListNext = NULL; + + // it is important to reserve the memory immediately, + // otherwise pointers would change while pushing back new arguments. + _variantArgs.reserve(PYTHONQT_MAX_ARGUMENT_FRAME_SIZE); + _podArgs.reserve(PYTHONQT_MAX_ARGUMENT_FRAME_SIZE); +} + +PythonQtArgumentFrame::~PythonQtArgumentFrame() +{ +} + +PythonQtArgumentFrame* PythonQtArgumentFrame::newFrame() +{ + PythonQtArgumentFrame* frame = NULL; + if (_freeListHead) { + frame = _freeListHead; + _freeListHead = _freeListHead->_freeListNext; + frame->_freeListNext = NULL; + } else { + frame = new PythonQtArgumentFrame(); + } + return frame; +} + +void PythonQtArgumentFrame::deleteFrame(PythonQtArgumentFrame* frame) +{ + frame->reset(); + frame->_freeListNext = _freeListHead; + _freeListHead = frame; +} + +void PythonQtArgumentFrame::cleanupFreeList() +{ + PythonQtArgumentFrame* head = _freeListHead; + while (head) { + PythonQtArgumentFrame* tmp = head; + head = head->_freeListNext; + delete tmp; + } + _freeListHead = NULL; +} + +void PythonQtArgumentFrame::reset() +{ + // Note: clear still keeps the capacity of the vectors, which is what we want! + _variantArgs.clear(); + _podArgs.clear(); +} + +QVariant* PythonQtArgumentFrame::nextVariantPtr() +{ + if (_variantArgs.size() >= PYTHONQT_MAX_ARGUMENT_FRAME_SIZE) { + std::cerr << "PYTHONQT_MAX_ARGUMENT_FRAME_SIZE QVariants exceeded, use less complex slots or increase size!" << std::endl; + } + _variantArgs.push_back(QVariant()); + return &_variantArgs[_variantArgs.size() - 1]; +} + +quint64* PythonQtArgumentFrame::nextPODPtr() +{ + if (_podArgs.size() >= PYTHONQT_MAX_ARGUMENT_FRAME_SIZE) { + std::cerr << "PYTHONQT_MAX_ARGUMENT_FRAME_SIZE PODs exceeded, use less complex slots or increase size!" << std::endl; + } + _podArgs.push_back(0); + return &_podArgs[_podArgs.size() - 1]; +} diff --git a/src/PythonQtMisc.h b/src/PythonQtMisc.h index cc67ed6dc..dc04a6679 100644 --- a/src/PythonQtMisc.h +++ b/src/PythonQtMisc.h @@ -43,133 +43,67 @@ //---------------------------------------------------------------------------------- #include "PythonQtPythonInclude.h" -#include +#include +#include -#define PythonQtValueStorage_ADD_VALUE(store, type, value, ptr) \ -{ type* item = (type*)store.nextValuePtr(); \ +#define PYTHONQT_MAX_ARGS 32 + +#define PythonQtArgumentFrame_ADD_VALUE(store, type, value, ptr) \ +{ type* item = (type*)store->nextPODPtr(); \ *item = value; \ ptr = (void*)item; \ } -#define PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, type, value, ptr) \ +#define PythonQtArgumentFrame_ADD_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, type, value, ptr) \ { \ - type* item = (type*)(alreadyAllocatedPtr?alreadyAllocatedPtr:store.nextValuePtr()); \ + type* item = (type*)(alreadyAllocatedPtr?alreadyAllocatedPtr:store->nextPODPtr()); \ *item = value; \ ptr = (void*)item; \ } -//! stores a position in the PythonQtValueStorage -class PythonQtValueStoragePosition { - -public: - PythonQtValueStoragePosition() { chunkIdx = 0; chunkOffset = 0; } +#define PythonQtArgumentFrame_ADD_VARIANT_VALUE(store, value, ptr) \ +{ QVariant* item = store->nextVariantPtr(); \ + *item = value; \ + ptr = (void*)item; \ +} - int chunkIdx; - int chunkOffset; +#define PythonQtArgumentFrame_ADD_VARIANT_VALUE_IF_NEEDED(alreadyAllocatedPtr,store, value, ptr) \ +{ \ + QVariant* item = (QVariant*)(alreadyAllocatedPtr?alreadyAllocatedPtr:store->nextVariantPtr()); \ + *item = value; \ + ptr = (void*)item; \ +} -}; +//! Stores C++ arguments for a qt_metacall (which are created when converting data from Python to C++) +class PythonQtArgumentFrame { -//! a helper class that stores basic C++ value types in chunks -template class PythonQtValueStorage -{ public: - PythonQtValueStorage() { - _chunkIdx = 0; - _chunkOffset = 0; - _currentChunk = new T[chunkEntries]; - _chunks.append(_currentChunk); - }; - - //! clear all memory - void clear() { - T* chunk; - Q_FOREACH(chunk, _chunks) { - delete[]chunk; - } - _chunks.clear(); - } - - //! get the current position to be restored with setPos - void getPos(PythonQtValueStoragePosition & pos) { - pos.chunkIdx = _chunkIdx; - pos.chunkOffset = _chunkOffset; - } - - //! set the current position (without freeing memory, thus caching old entries for reuse) - void setPos(const PythonQtValueStoragePosition& pos) { - _chunkOffset = pos.chunkOffset; - if (_chunkIdx != pos.chunkIdx) { - _chunkIdx = pos.chunkIdx; - _currentChunk = _chunks.at(_chunkIdx); - } - } - - //! add one default constructed value and return the pointer to it - T* nextValuePtr() { - if (_chunkOffset>=chunkEntries) { - _chunkIdx++; - if (_chunkIdx >= _chunks.size()) { - T* newChunk = new T[chunkEntries]; - _chunks.append(newChunk); - _currentChunk = newChunk; - } else { - _currentChunk = _chunks.at(_chunkIdx); - } - _chunkOffset = 0; - } - T* newEntry = _currentChunk + _chunkOffset; - _chunkOffset++; - return newEntry; - }; - -protected: - QList _chunks; - - int _chunkIdx; - int _chunkOffset; - T* _currentChunk; + //! Create a new (empty) frame (which is typically reused from a freelist) + static PythonQtArgumentFrame* newFrame(); + //! Frees the frame (resetting it and putting it back to the freelist) + static void deleteFrame(PythonQtArgumentFrame* frame); -}; + //! Frees all PythonQtArgumentFrame frames that are stored. + static void cleanupFreeList(); -//! a helper class that stores basic C++ value types in chunks and clears the unused values on setPos() usage. -template class PythonQtValueStorageWithCleanup : public PythonQtValueStorage -{ -public: - void setPos(const PythonQtValueStoragePosition& pos) { - if (_chunkIdx > pos.chunkIdx) { - T* firstChunk = _chunks.at(pos.chunkIdx); - // clear region in first chunk - for (int i = pos.chunkOffset; i < chunkEntries; i++) { - firstChunk[i] = T(); - } - for (int chunk = pos.chunkIdx + 1; chunk < _chunkIdx; chunk++) { - // clear the full chunks between the first and last chunk - T* fullChunk = _chunks.at(chunk); - for (int i = 0; i < chunkEntries; i++) { - fullChunk[i] = T(); - } - } - // clear region in last chunk - T* lastChunk = _chunks.at(_chunkIdx); - for (int i = 0; i < _chunkOffset; i++) { - lastChunk[i] = T(); - } - } else if (_chunkIdx == pos.chunkIdx) { - // clear the region in the last chunk only - T* lastChunk = _chunks.at(_chunkIdx); - for (int i = pos.chunkOffset; i<_chunkOffset; i++) { - lastChunk[i] = T(); - } - } - - PythonQtValueStorage::setPos(pos); - } + //! Resets the pod and variant argument lists to empty lists. + void reset(); + + //! Get next pointer to a variant + QVariant* nextVariantPtr(); + //! Get next pointer to a POD. + quint64* nextPODPtr(); private: - using PythonQtValueStorage::_chunks; - using PythonQtValueStorage::_chunkIdx; - using PythonQtValueStorage::_chunkOffset; - using PythonQtValueStorage::_currentChunk; + PythonQtArgumentFrame(); + ~PythonQtArgumentFrame(); + + std::vector _podArgs; + std::vector _variantArgs; + + PythonQtArgumentFrame* _freeListNext; + + static PythonQtArgumentFrame* _freeListHead; }; #endif diff --git a/src/PythonQtSlot.cpp b/src/PythonQtSlot.cpp index f9bff95fc..9d720b08e 100644 --- a/src/PythonQtSlot.cpp +++ b/src/PythonQtSlot.cpp @@ -56,26 +56,12 @@ #include #endif -#define PYTHONQT_MAX_ARGS 32 - - bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObject* args, bool strict, PythonQtSlotInfo* info, void* firstArgument, PyObject** pythonReturnValue, void** directReturnValuePointer, PythonQtPassThisOwnershipType* passThisOwnershipToCPP) { - static unsigned int recursiveEntry = 0; - if (directReturnValuePointer) { *directReturnValuePointer = NULL; } - // store the current storage position, so that we can get back to this state after a slot is called - // (do this locally, so that we have all positions on the stack - PythonQtValueStoragePosition globalValueStoragePos; - PythonQtValueStoragePosition globalPtrStoragePos; - PythonQtValueStoragePosition globalVariantStoragePos; - PythonQtConv::global_valueStorage.getPos(globalValueStoragePos); - PythonQtConv::global_ptrStorage.getPos(globalPtrStoragePos); - PythonQtConv::global_variantStorage.getPos(globalVariantStoragePos); - - recursiveEntry++; + PythonQtArgumentFrame* frame = PythonQtArgumentFrame::newFrame(); // the arguments that are passed to qt_metacall void* argList[PYTHONQT_MAX_ARGS]; @@ -115,7 +101,7 @@ bool PythonQtCallSlot(PythonQtClassInfo* classInfo, QObject* objectToCall, PyObj } for (int i = 1 + instanceDecoOffset; i