From a713e377bbc0cdbceb3b90b32037a6f28c68c0e1 Mon Sep 17 00:00:00 2001 From: Renato Filho Date: Wed, 3 Aug 2011 20:16:20 -0300 Subject: DynamicMetaObject optimizations. Reviewer: Marcelo Lira Luciano Wolf --- libpyside/dynamicqmetaobject.cpp | 207 ++++++++++++++++++++++++++++----------- 1 file changed, 149 insertions(+), 58 deletions(-) (limited to 'libpyside') diff --git a/libpyside/dynamicqmetaobject.cpp b/libpyside/dynamicqmetaobject.cpp index 5476a379a..8b8998b0c 100644 --- a/libpyside/dynamicqmetaobject.cpp +++ b/libpyside/dynamicqmetaobject.cpp @@ -85,29 +85,46 @@ class DynamicQMetaObject::DynamicQMetaObjectPrivate public: QList m_methods; QList m_properties; + + // methods added/remove not writed on metadata yet + int m_lastMethod; + int m_lastProperty; + int m_lastInfo; + QMap m_info; QByteArray m_className; - bool m_invalid; + bool m_updated; // when the meta data is not update + bool m_invalid; // when the object need to be reconstructed int m_methodOffset; int m_propertyOffset; int m_count; + int m_dataSize; + int m_stringDataSize; + int m_emptyMethod; + int m_nullIndex; + + DynamicQMetaObjectPrivate() + : m_lastMethod(0), m_lastProperty(0), m_lastInfo(0), + m_updated(false), m_invalid(true), m_methodOffset(0), m_propertyOffset(0), + m_count(0), m_dataSize(0), m_stringDataSize(0), m_emptyMethod(-1), m_nullIndex(0) {} + int createMetaData(QMetaObject* metaObj, QLinkedList &strings); void updateMetaObject(QMetaObject* metaObj); - void writeMethodsData(const QList& methods, unsigned int** data, QLinkedList* strings, int* prtIndex, int nullIndex, int flags); + void writeMethodsData(const QList& methods, unsigned int** data, QLinkedList& strings, int* prtIndex, int nullIndex, int flags); }; -static int registerString(const QByteArray& s, QLinkedList* strings) +static int registerString(const QByteArray& s, QLinkedList& strings) { int idx = 0; - QLinkedList::const_iterator it = strings->begin(); - QLinkedList::const_iterator itEnd = strings->end(); + QLinkedList::const_iterator it = strings.begin(); + QLinkedList::const_iterator itEnd = strings.end(); while (it != itEnd) { if (strcmp(*it, s) == 0) return idx; idx += it->size() + 1; ++it; } - strings->append(s); + strings.append(s); return idx; } @@ -223,7 +240,7 @@ void MethodData::clear() bool MethodData::isValid() const { - return m_signature.size(); + return m_signature != m_emptySig; } QMetaMethod::MethodType MethodData::methodType() const @@ -277,10 +294,8 @@ DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* ba d.extradata = NULL; m_d->m_className = QByteArray(type->tp_name).split('.').last(); - m_d->m_invalid = true; m_d->m_methodOffset = base->methodCount() - 1; m_d->m_propertyOffset = base->propertyCount() - 1; - m_d->m_count = 0; parsePythonType(type); } @@ -291,8 +306,6 @@ DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* d.stringdata = 0; d.data = 0; d.extradata = 0; - m_d->m_count = 0; - m_d->m_invalid = true; m_d->m_className = className; m_d->m_methodOffset = metaObject->methodCount() - 1; m_d->m_propertyOffset = metaObject->propertyCount() - 1; @@ -309,26 +322,28 @@ int DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* sig { int index = -1; int counter = 0; - MethodData blank; QList::iterator it = m_d->m_methods.begin(); for (; it != m_d->m_methods.end(); ++it) { if ((it->signature() == signature) && (it->methodType() == mtype)) return m_d->m_methodOffset + counter; - else if (*it == blank) + else if (!it->isValid()) { index = counter; + m_d->m_invalid = true; // need rewrite all methods again + } counter++; } //has blank method if (index != -1) { m_d->m_methods[index] = MethodData(mtype, signature, type); + index++; } else { m_d->m_methods << MethodData(mtype, signature, type); index = m_d->m_methods.size(); } - m_d->m_invalid = true; + m_d->m_updated = false; return m_d->m_methodOffset + index; } @@ -387,11 +402,12 @@ int DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data) index = m_d->m_properties.indexOf(blank); if (index != -1) { m_d->m_properties[index] = PropertyData(propertyName, notifyId, property); + m_d->m_invalid = true; } else { m_d->m_properties << PropertyData(propertyName, notifyId, property); index = m_d->m_properties.size(); } - m_d->m_invalid = true; + m_d->m_updated = false; return m_d->m_propertyOffset + index; } @@ -407,40 +423,47 @@ void DynamicQMetaObject::addInfo(QMap info) m_d->m_info[i.key()] = i.value(); ++i; } - m_d->m_invalid = true; + m_d->m_updated = false; } const QMetaObject* DynamicQMetaObject::update() const { - if (m_d->m_invalid) { + if (!m_d->m_updated || m_d->m_invalid) { m_d->updateMetaObject(const_cast(this)); - m_d->m_invalid = false; + m_d->m_updated = true; } return this; } void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList& methods, unsigned int** data, - QLinkedList* strings, + QLinkedList& strings, int* prtIndex, int nullIndex, int flags) { int index = *prtIndex; - int emptyIndex = registerString(EMPTY_META_METHOD, strings); - QList::const_iterator it = methods.begin(); + //skip to last registered method + QList::const_iterator it = methods.begin() + m_lastMethod; + + if (m_emptyMethod == -1) + m_emptyMethod = registerString(EMPTY_META_METHOD, strings) + m_stringDataSize; for (; it != methods.end(); ++it) { if (it->signature() != EMPTY_META_METHOD) - (*data)[index++] = registerString(it->signature(), strings); // func name + (*data)[index++] = registerString(it->signature(), strings) + m_stringDataSize; // func name else - (*data)[index++] = emptyIndex; // func name + (*data)[index++] = m_emptyMethod; // func name + (*data)[index++] = nullIndex; // arguments (*data)[index++] = (it->type().size() > 0 ? registerString(it->type(), strings) : nullIndex); // normalized type (*data)[index++] = nullIndex; // tags (*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot); } *prtIndex = index; + + //update last registered method + m_lastMethod = methods.size(); } void DynamicQMetaObject::parsePythonType(PyTypeObject* type) @@ -496,7 +519,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject* type) } -void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj) +int DynamicQMetaObject::DynamicQMetaObjectPrivate::createMetaData(QMetaObject* metaObj, QLinkedList &strings) { uint n_methods = m_methods.size(); uint n_properties = m_properties.size(); @@ -511,66 +534,134 @@ void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject 0}; // flags const int HEADER_LENGHT = sizeof(header)/sizeof(int); - header[5] = HEADER_LENGHT; - // header size + 5 indexes per method + an ending zero - - const int dataSize = HEADER_LENGHT + n_methods*5 + n_properties*4 + n_info*2 + 1; - uint* data = reinterpret_cast(realloc(const_cast(metaObj->d.data), dataSize * sizeof(uint))); + m_dataSize = HEADER_LENGHT + n_methods*5 + n_properties*4 + n_info*2 + 1; + uint* data = reinterpret_cast(realloc(const_cast(metaObj->d.data), m_dataSize * sizeof(uint))); + Q_ASSERT(data); std::memcpy(data, header, sizeof(header)); + registerString(m_className, strings); // register class string + m_nullIndex = registerString("", strings); // register a null string + + metaObj->d.data = data; + + return HEADER_LENGHT; +} + + +void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj) +{ + uint *data = const_cast(metaObj->d.data); + int index = m_dataSize - 1; // remove the last 0 QLinkedList strings; - registerString(m_className, &strings); // register class string - const int NULL_INDEX = registerString("", &strings); // register a null string - int index = HEADER_LENGHT; + + if (!data || m_invalid) { + if (m_invalid) { + strings.clear(); + m_dataSize = m_stringDataSize = 0; + m_lastMethod = m_lastInfo = m_lastProperty = 0; + m_invalid = false; + } + + index = createMetaData(metaObj, strings); + data = const_cast(metaObj->d.data); + } else { + int n_methods = m_methods.size() - m_lastMethod; + int n_info = m_info.size() - m_lastInfo; + uint n_properties = m_properties.size() - m_lastProperty; + + int extraSize = n_methods*5 + n_properties*4 + n_info*2; + if (extraSize > 0) { + m_dataSize += extraSize; + //realloc data + data = reinterpret_cast(realloc(const_cast(metaObj->d.data), m_dataSize * sizeof(uint))); + Q_ASSERT(data); + + + data[2] = m_info.size(); //update info size + data[4] = m_methods.size(); //update number of methods + data[6] = m_properties.size(); // update property size + metaObj->d.data = data; + } else { + data = const_cast(metaObj->d.data); + } + } //write class info - if (n_info) { - data[3] = index; - QMap::const_iterator i = m_info.constBegin(); + if (m_info.size()) { + if (data[3] == 0) + data[3] = index; + + QMap::const_iterator i = m_info.constBegin() + m_lastInfo; //TODO: info is a hash this can fail while (i != m_info.constEnd()) { - int valueIndex = registerString(i.value(), &strings); - int keyIndex = registerString(i.key(), &strings); - data[index++] = keyIndex; - data[index++] = valueIndex; + int valueIndex = registerString(i.value(), strings); + int keyIndex = registerString(i.key(), strings); + data[index++] = keyIndex + m_stringDataSize; + data[index++] = valueIndex + m_stringDataSize; i++; } - } - //write signals/slots - if (n_methods) - writeMethodsData(m_methods, &data, &strings, &index, NULL_INDEX, AccessPublic); - - if (m_properties.size()) - data[7] = index; + m_lastInfo = m_info.size(); + } //write properties - foreach(PropertyData pp, m_properties) { - if (pp.isValid()) - data[index++] = registerString(pp.name(), &strings); // name - else - data[index++] = NULL_INDEX; + if (m_properties.size()) { + if (data[7] == 0) + data[7] = index; + + QList::const_iterator i = m_properties.constBegin() + m_lastProperty; + while(i != m_properties.constEnd()) { + if (i->isValid()) { + data[index++] = registerString(i->name(), strings) + m_stringDataSize; // name + } else + data[index++] = m_nullIndex; + + data[index++] = (i->isValid() ? (registerString(i->type(), strings) + m_stringDataSize) : m_nullIndex); // normalized type + data[index++] = i->flags(); + i++; + } - data[index++] = (pp.isValid() ? registerString(pp.type(), &strings) : NULL_INDEX); // normalized type - data[index++] = pp.flags(); + //write properties notify + i = m_properties.constBegin() + m_lastProperty; + while(i != m_properties.constEnd()) { + data[index++] = i->notifyId() >= 0 ? i->notifyId() : 0; //signal notify index + i++; + } + + m_lastProperty = m_properties.size(); } - //write properties notify - foreach(PropertyData pp, m_properties) - data[index++] = pp.notifyId() >= 0 ? pp.notifyId() : 0; //signal notify index + //write signals/slots + if (m_methods.size()) { + if (data[5] == 0) + data[5] = index; + + writeMethodsData(m_methods, &data, strings, &index, m_nullIndex, AccessPublic); + } data[index++] = 0; // the end // create the m_metadata string QByteArray str; + QByteArray debugStr; foreach(QByteArray field, strings) { + + debugStr.append(field); + debugStr.append('|'); + str.append(field); str.append(char(0)); } - char *stringdata = reinterpret_cast(realloc(const_cast(metaObj->d.stringdata), str.count() * sizeof(char))); + int newSize = (m_stringDataSize + str.count()) * sizeof(char); + char *stringdata = reinterpret_cast(realloc(const_cast(metaObj->d.stringdata), newSize)); + Q_ASSERT(stringdata); + + metaObj->d.stringdata = stringdata; + + stringdata += m_stringDataSize; //shift to the end of old position std::copy(str.begin(), str.end(), stringdata); + m_stringDataSize = newSize; metaObj->d.data = data; - metaObj->d.stringdata = stringdata; } -- cgit v1.2.3