mirror of
https://github.com/lubosz/overte.git
synced 2025-04-13 03:53:09 +02:00
More work on version-resilient type streaming.
This commit is contained in:
parent
61660f890e
commit
d8b83fd308
3 changed files with 302 additions and 36 deletions
|
@ -82,6 +82,10 @@ int Bitstream::registerTypeStreamer(int type, TypeStreamer* streamer) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const TypeStreamer* Bitstream::getTypeStreamer(int type) {
|
||||
return getTypeStreamers().value(type);
|
||||
}
|
||||
|
||||
const QMetaObject* Bitstream::getMetaObject(const QByteArray& className) {
|
||||
return getMetaObjects().value(className);
|
||||
}
|
||||
|
@ -325,11 +329,9 @@ Bitstream& Bitstream::operator<<(const QVariant& value) {
|
|||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(QVariant& value) {
|
||||
const TypeStreamer* streamer;
|
||||
_typeStreamerStreamer >> streamer;
|
||||
if (streamer) {
|
||||
value = streamer->read(*this);
|
||||
}
|
||||
TypeReader reader;
|
||||
_typeStreamerStreamer >> reader;
|
||||
value = reader.read(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -406,7 +408,14 @@ Bitstream& Bitstream::operator<<(const TypeStreamer* streamer) {
|
|||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(const TypeStreamer*& streamer) {
|
||||
_typeStreamerStreamer >> streamer;
|
||||
TypeReader typeReader;
|
||||
_typeStreamerStreamer >> typeReader;
|
||||
streamer = typeReader.getStreamer();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>>(TypeReader& reader) {
|
||||
_typeStreamerStreamer >> reader;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -499,8 +508,8 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
*this >> storedPropertyCount;
|
||||
QVector<PropertyReader> properties(storedPropertyCount);
|
||||
for (int i = 0; i < storedPropertyCount; i++) {
|
||||
const TypeStreamer* typeStreamer;
|
||||
*this >> typeStreamer;
|
||||
TypeReader typeReader;
|
||||
*this >> typeReader;
|
||||
QMetaProperty property = QMetaProperty();
|
||||
if (_metadataType == FULL_METADATA) {
|
||||
QByteArray propertyName;
|
||||
|
@ -509,7 +518,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
property = metaObject->property(metaObject->indexOfProperty(propertyName));
|
||||
}
|
||||
}
|
||||
properties[i] = PropertyReader(typeStreamer, property);
|
||||
properties[i] = PropertyReader(typeReader, property);
|
||||
}
|
||||
// for hash metadata, check the names/types of the properties as well as the name hash against our own class
|
||||
if (_metadataType == HASH_METADATA) {
|
||||
|
@ -525,7 +534,8 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
if (!typeStreamer) {
|
||||
continue;
|
||||
}
|
||||
if (propertyIndex >= properties.size() || properties.at(propertyIndex).getStreamer() != typeStreamer) {
|
||||
if (propertyIndex >= properties.size() ||
|
||||
!properties.at(propertyIndex).getReader().matchesExactly(typeStreamer)) {
|
||||
objectReader = ObjectReader(className, metaObject, properties);
|
||||
return *this;
|
||||
}
|
||||
|
@ -551,16 +561,106 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
|
|||
|
||||
Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
|
||||
const char* typeName = QMetaType::typeName(streamer->getType());
|
||||
return *this << QByteArray::fromRawData(typeName, strlen(typeName));
|
||||
*this << QByteArray::fromRawData(typeName, strlen(typeName));
|
||||
if (_metadataType == NO_METADATA) {
|
||||
return *this;
|
||||
}
|
||||
const QVector<MetaField>& metaFields = streamer->getMetaFields();
|
||||
*this << metaFields.size();
|
||||
if (metaFields.isEmpty()) {
|
||||
return *this;
|
||||
}
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
foreach (const MetaField& metaField, metaFields) {
|
||||
_typeStreamerStreamer << metaField.getStreamer();
|
||||
if (_metadataType == FULL_METADATA) {
|
||||
*this << metaField.getName();
|
||||
} else {
|
||||
hash.addData(metaField.getName().constData(), metaField.getName().size() + 1);
|
||||
}
|
||||
}
|
||||
if (_metadataType == HASH_METADATA) {
|
||||
QByteArray hashResult = hash.result();
|
||||
write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bitstream& Bitstream::operator>(const TypeStreamer*& streamer) {
|
||||
Bitstream& Bitstream::operator>(TypeReader& reader) {
|
||||
QByteArray typeName;
|
||||
*this >> typeName;
|
||||
streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
|
||||
const TypeStreamer* streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
|
||||
if (!streamer) {
|
||||
qWarning() << "Unknown type name: " << typeName << "\n";
|
||||
}
|
||||
if (_metadataType == NO_METADATA) {
|
||||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
}
|
||||
int fieldCount;
|
||||
*this >> fieldCount;
|
||||
QVector<FieldReader> fields(fieldCount);
|
||||
for (int i = 0; i < fieldCount; i++) {
|
||||
TypeReader typeReader;
|
||||
*this >> typeReader;
|
||||
int index = -1;
|
||||
if (_metadataType == FULL_METADATA) {
|
||||
QByteArray fieldName;
|
||||
*this >> fieldName;
|
||||
if (streamer) {
|
||||
index = streamer->getFieldIndex(fieldName);
|
||||
}
|
||||
}
|
||||
fields[i] = FieldReader(typeReader, index);
|
||||
}
|
||||
// for hash metadata, check the names/types of the fields as well as the name hash against our own class
|
||||
if (_metadataType == HASH_METADATA) {
|
||||
QCryptographicHash hash(QCryptographicHash::Md5);
|
||||
if (streamer) {
|
||||
const QVector<MetaField>& localFields = streamer->getMetaFields();
|
||||
if (fieldCount != localFields.size()) {
|
||||
reader = TypeReader(typeName, streamer, false, fields);
|
||||
return *this;
|
||||
}
|
||||
if (fieldCount == 0) {
|
||||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
}
|
||||
for (int i = 0; i < fieldCount; i++) {
|
||||
const MetaField& localField = localFields.at(i);
|
||||
if (!fields.at(i).getReader().matchesExactly(localField.getStreamer())) {
|
||||
reader = TypeReader(typeName, streamer, false, fields);
|
||||
return *this;
|
||||
}
|
||||
hash.addData(localField.getName().constData(), localField.getName().size() + 1);
|
||||
}
|
||||
}
|
||||
QByteArray localHashResult = hash.result();
|
||||
QByteArray remoteHashResult(localHashResult.size(), 0);
|
||||
read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE);
|
||||
if (streamer && localHashResult == remoteHashResult) {
|
||||
// since everything is the same, we can use the default streamer
|
||||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
}
|
||||
} else if (streamer) {
|
||||
// if all fields are the same type and in the right order, we can use the (more efficient) default streamer
|
||||
const QVector<MetaField>& localFields = streamer->getMetaFields();
|
||||
if (fieldCount != localFields.size()) {
|
||||
reader = TypeReader(typeName, streamer, false, fields);
|
||||
return *this;
|
||||
}
|
||||
for (int i = 0; i < fieldCount; i++) {
|
||||
const FieldReader& fieldReader = fields.at(i);
|
||||
if (!fieldReader.getReader().matchesExactly(localFields.at(i).getStreamer()) || fieldReader.getIndex() != i) {
|
||||
reader = TypeReader(typeName, streamer, false, fields);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
}
|
||||
reader = TypeReader(typeName, streamer, false, fields);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -650,12 +750,51 @@ QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObj
|
|||
}
|
||||
const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType());
|
||||
if (typeStreamer) {
|
||||
propertyReaders.append(PropertyReader(typeStreamer, property));
|
||||
propertyReaders.append(PropertyReader(TypeReader(QByteArray(), typeStreamer), property));
|
||||
}
|
||||
}
|
||||
return propertyReaders;
|
||||
}
|
||||
|
||||
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer,
|
||||
bool exactMatch, const QVector<FieldReader>& fields) :
|
||||
_typeName(typeName),
|
||||
_streamer(streamer),
|
||||
_exactMatch(exactMatch),
|
||||
_fields(fields) {
|
||||
}
|
||||
|
||||
QVariant TypeReader::read(Bitstream& in) const {
|
||||
if (_exactMatch) {
|
||||
return _streamer->read(in);
|
||||
}
|
||||
QVariant object = _streamer ? QVariant(_streamer->getType(), 0) : QVariant();
|
||||
foreach (const FieldReader& field, _fields) {
|
||||
field.read(in, _streamer, object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
bool TypeReader::matchesExactly(const TypeStreamer* streamer) const {
|
||||
return _exactMatch && _streamer == streamer;
|
||||
}
|
||||
|
||||
uint qHash(const TypeReader& typeReader, uint seed) {
|
||||
return qHash(typeReader.getTypeName(), seed);
|
||||
}
|
||||
|
||||
FieldReader::FieldReader(const TypeReader& reader, int index) :
|
||||
_reader(reader),
|
||||
_index(index) {
|
||||
}
|
||||
|
||||
void FieldReader::read(Bitstream& in, const TypeStreamer* streamer, QVariant& object) const {
|
||||
QVariant value = _reader.read(in);
|
||||
if (_index != -1 && streamer) {
|
||||
streamer->setField(_index, object, value);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject,
|
||||
const QVector<PropertyReader>& properties) :
|
||||
_className(className),
|
||||
|
@ -677,14 +816,35 @@ uint qHash(const ObjectReader& objectReader, uint seed) {
|
|||
return qHash(objectReader.getClassName(), seed);
|
||||
}
|
||||
|
||||
PropertyReader::PropertyReader(const TypeStreamer* streamer, const QMetaProperty& property) :
|
||||
_streamer(streamer),
|
||||
PropertyReader::PropertyReader(const TypeReader& reader, const QMetaProperty& property) :
|
||||
_reader(reader),
|
||||
_property(property) {
|
||||
}
|
||||
|
||||
void PropertyReader::read(Bitstream& in, QObject* object) const {
|
||||
QVariant value = _streamer->read(in);
|
||||
QVariant value = _reader.read(in);
|
||||
if (_property.isValid() && object) {
|
||||
_property.write(object, value);
|
||||
}
|
||||
}
|
||||
|
||||
MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) :
|
||||
_name(name),
|
||||
_streamer(streamer) {
|
||||
}
|
||||
|
||||
TypeStreamer::~TypeStreamer() {
|
||||
}
|
||||
|
||||
const QVector<MetaField>& TypeStreamer::getMetaFields() const {
|
||||
static QVector<MetaField> emptyMetaFields;
|
||||
return emptyMetaFields;
|
||||
}
|
||||
|
||||
int TypeStreamer::getFieldIndex(const QByteArray& name) const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TypeStreamer::setField(int index, QVariant& object, const QVariant& value) const {
|
||||
// nothing by default
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QScriptString>
|
||||
#include <QSharedPointer>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -30,9 +31,11 @@ class QUrl;
|
|||
class Attribute;
|
||||
class AttributeValue;
|
||||
class Bitstream;
|
||||
class FieldReader;
|
||||
class ObjectReader;
|
||||
class OwnedAttributeValue;
|
||||
class PropertyReader;
|
||||
class TypeReader;
|
||||
class TypeStreamer;
|
||||
|
||||
typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
|
||||
|
@ -191,7 +194,7 @@ public:
|
|||
class ReadMappings {
|
||||
public:
|
||||
QHash<int, ObjectReader> metaObjectValues;
|
||||
QHash<int, const TypeStreamer*> typeStreamerValues;
|
||||
QHash<int, TypeReader> typeStreamerValues;
|
||||
QHash<int, AttributePointer> attributeValues;
|
||||
QHash<int, QScriptString> scriptStringValues;
|
||||
QHash<int, SharedObjectPointer> sharedObjectValues;
|
||||
|
@ -205,6 +208,9 @@ public:
|
|||
/// \return zero; the function only returns a value so that it can be used in static initialization
|
||||
static int registerTypeStreamer(int type, TypeStreamer* streamer);
|
||||
|
||||
/// Returns the streamer registered for the supplied type, if any.
|
||||
static const TypeStreamer* getTypeStreamer(int type);
|
||||
|
||||
/// Returns the meta-object registered under the supplied class name, if any.
|
||||
static const QMetaObject* getMetaObject(const QByteArray& className);
|
||||
|
||||
|
@ -307,6 +313,7 @@ public:
|
|||
|
||||
Bitstream& operator<<(const TypeStreamer* streamer);
|
||||
Bitstream& operator>>(const TypeStreamer*& streamer);
|
||||
Bitstream& operator>>(TypeReader& reader);
|
||||
|
||||
Bitstream& operator<<(const AttributePointer& attribute);
|
||||
Bitstream& operator>>(AttributePointer& attribute);
|
||||
|
@ -321,7 +328,7 @@ public:
|
|||
Bitstream& operator>(ObjectReader& objectReader);
|
||||
|
||||
Bitstream& operator<(const TypeStreamer* streamer);
|
||||
Bitstream& operator>(const TypeStreamer*& streamer);
|
||||
Bitstream& operator>(TypeReader& reader);
|
||||
|
||||
Bitstream& operator<(const AttributePointer& attribute);
|
||||
Bitstream& operator>(AttributePointer& attribute);
|
||||
|
@ -349,7 +356,7 @@ private:
|
|||
MetadataType _metadataType;
|
||||
|
||||
RepeatedValueStreamer<const QMetaObject*, const QMetaObject*, ObjectReader> _metaObjectStreamer;
|
||||
RepeatedValueStreamer<const TypeStreamer*> _typeStreamerStreamer;
|
||||
RepeatedValueStreamer<const TypeStreamer*, const TypeStreamer*, TypeReader> _typeStreamerStreamer;
|
||||
RepeatedValueStreamer<AttributePointer> _attributeStreamer;
|
||||
RepeatedValueStreamer<QScriptString> _scriptStringStreamer;
|
||||
RepeatedValueStreamer<SharedObjectPointer, SharedObject*> _sharedObjectStreamer;
|
||||
|
@ -428,6 +435,50 @@ template<class K, class V> inline Bitstream& Bitstream::operator>>(QHash<K, V>&
|
|||
return *this;
|
||||
}
|
||||
|
||||
/// Contains the information required to read a type from the stream.
|
||||
class TypeReader {
|
||||
public:
|
||||
|
||||
TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL,
|
||||
bool exactMatch = true, const QVector<FieldReader>& fields = QVector<FieldReader>());
|
||||
|
||||
const QByteArray& getTypeName() const { return _typeName; }
|
||||
const TypeStreamer* getStreamer() const { return _streamer; }
|
||||
|
||||
QVariant read(Bitstream& in) const;
|
||||
|
||||
bool matchesExactly(const TypeStreamer* streamer) const;
|
||||
|
||||
bool operator==(const TypeReader& other) const { return _typeName == other._typeName; }
|
||||
bool operator!=(const TypeReader& other) const { return _typeName != other._typeName; }
|
||||
|
||||
private:
|
||||
|
||||
QByteArray _typeName;
|
||||
const TypeStreamer* _streamer;
|
||||
bool _exactMatch;
|
||||
QVector<FieldReader> _fields;
|
||||
};
|
||||
|
||||
uint qHash(const TypeReader& typeReader, uint seed = 0);
|
||||
|
||||
/// Contains the information required to read a metatype field from the stream and apply it.
|
||||
class FieldReader {
|
||||
public:
|
||||
|
||||
FieldReader(const TypeReader& reader = TypeReader(), int index = -1);
|
||||
|
||||
const TypeReader& getReader() const { return _reader; }
|
||||
int getIndex() const { return _index; }
|
||||
|
||||
void read(Bitstream& in, const TypeStreamer* streamer, QVariant& object) const;
|
||||
|
||||
private:
|
||||
|
||||
TypeReader _reader;
|
||||
int _index;
|
||||
};
|
||||
|
||||
/// Contains the information required to read an object from the stream.
|
||||
class ObjectReader {
|
||||
public:
|
||||
|
@ -438,8 +489,6 @@ public:
|
|||
const QByteArray& getClassName() const { return _className; }
|
||||
const QMetaObject* getMetaObject() const { return _metaObject; }
|
||||
|
||||
bool isNull() const { return _className.isEmpty(); }
|
||||
|
||||
QObject* read(Bitstream& in, QObject* object = NULL) const;
|
||||
|
||||
bool operator==(const ObjectReader& other) const { return _className == other._className; }
|
||||
|
@ -458,18 +507,33 @@ uint qHash(const ObjectReader& objectReader, uint seed = 0);
|
|||
class PropertyReader {
|
||||
public:
|
||||
|
||||
PropertyReader(const TypeStreamer* streamer = NULL, const QMetaProperty& property = QMetaProperty());
|
||||
PropertyReader(const TypeReader& reader = TypeReader(), const QMetaProperty& property = QMetaProperty());
|
||||
|
||||
const TypeStreamer* getStreamer() const { return _streamer; }
|
||||
const TypeReader& getReader() const { return _reader; }
|
||||
|
||||
void read(Bitstream& in, QObject* object) const;
|
||||
|
||||
private:
|
||||
|
||||
const TypeStreamer* _streamer;
|
||||
TypeReader _reader;
|
||||
QMetaProperty _property;
|
||||
};
|
||||
|
||||
/// Describes a metatype field.
|
||||
class MetaField {
|
||||
public:
|
||||
|
||||
MetaField(const QByteArray& name = QByteArray(), const TypeStreamer* streamer = NULL);
|
||||
|
||||
const QByteArray& getName() const { return _name; }
|
||||
const TypeStreamer* getStreamer() const { return _streamer; }
|
||||
|
||||
private:
|
||||
|
||||
QByteArray _name;
|
||||
const TypeStreamer* _streamer;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(const QMetaObject*)
|
||||
|
||||
/// Macro for registering streamable meta-objects.
|
||||
|
@ -479,12 +543,18 @@ Q_DECLARE_METATYPE(const QMetaObject*)
|
|||
class TypeStreamer {
|
||||
public:
|
||||
|
||||
virtual ~TypeStreamer();
|
||||
|
||||
void setType(int type) { _type = type; }
|
||||
int getType() const { return _type; }
|
||||
|
||||
virtual void write(Bitstream& out, const QVariant& value) const = 0;
|
||||
virtual QVariant read(Bitstream& in) const = 0;
|
||||
|
||||
virtual const QVector<MetaField>& getMetaFields() const;
|
||||
virtual int getFieldIndex(const QByteArray& name) const;
|
||||
virtual void setField(int index, QVariant& object, const QVariant& value) const;
|
||||
|
||||
private:
|
||||
|
||||
int _type;
|
||||
|
@ -498,6 +568,16 @@ public:
|
|||
virtual QVariant read(Bitstream& in) const { T value; in >> value; return QVariant::fromValue(value); }
|
||||
};
|
||||
|
||||
/// A streamer that works with Bitstream's operators.
|
||||
template<class T> class CompoundTypeStreamer : public SimpleTypeStreamer<T> {
|
||||
public:
|
||||
|
||||
virtual const QVector<MetaField>& getMetaFields() const { return T::getMetaFields(); }
|
||||
virtual int getFieldIndex(const QByteArray& name) const { return T::getFieldIndex(name); }
|
||||
virtual void setField(int index, QVariant& object, const QVariant& value) const {
|
||||
static_cast<T*>(object.data())->setField(index, value); }
|
||||
};
|
||||
|
||||
/// Macro for registering simple type streamers.
|
||||
#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \
|
||||
Bitstream::registerTypeStreamer(QMetaType::type(#x), new SimpleTypeStreamer<x>());
|
||||
|
@ -532,16 +612,18 @@ public:
|
|||
/// Registers a streamable type and its streamer.
|
||||
template<class T> int registerStreamableMetaType() {
|
||||
int type = qRegisterMetaType<T>();
|
||||
Bitstream::registerTypeStreamer(type, new SimpleTypeStreamer<T>());
|
||||
Bitstream::registerTypeStreamer(type, new CompoundTypeStreamer<T>());
|
||||
return type;
|
||||
}
|
||||
|
||||
/// Flags a class as streamable (use as you would Q_OBJECT).
|
||||
#define STREAMABLE public: \
|
||||
static const int Type; \
|
||||
static int getFieldCount(); \
|
||||
void setFieldValue(int index, const QVariant& value); \
|
||||
private:
|
||||
static const QVector<MetaField>& getMetaFields(); \
|
||||
static int getFieldIndex(const QByteArray& name); \
|
||||
void setField(int index, const QVariant& value); \
|
||||
private: \
|
||||
static QHash<QByteArray, int> createFieldIndices();
|
||||
|
||||
/// Flags a field or base class as streaming.
|
||||
#define STREAM
|
||||
|
|
|
@ -100,21 +100,45 @@ void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
|||
|
||||
out << "const int " << name << "::Type = registerStreamableMetaType<" << name << ">();\n";
|
||||
|
||||
out << "int " << name << "::getFieldCount() {\n";
|
||||
out << " return " << str.fields.size();
|
||||
foreach(const QString& base, str.clazz.bases) {
|
||||
out << " + " << base << "::getFieldCount()";
|
||||
out << "const QVector<MetaField>& " << name << "::getMetaFields() {\n";
|
||||
out << " static QVector<MetaField> metaFields = QVector<MetaField>()";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " << " << base << "::getMetaFields()";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << "\n << MetaField(\"" << field.name << "\", Bitstream::getTypeStreamer(qMetaTypeId<" <<
|
||||
field.type << ">()))";
|
||||
}
|
||||
out << ";\n";
|
||||
out << " return metaFields;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "void " << name << "::setFieldValue(int index, const QVariant& value) {\n";
|
||||
out << "int " << name << "::getFieldIndex(const QByteArray& name) {\n";
|
||||
out << " static QHash<QByteArray, int> fieldIndices = createFieldIndices();\n";
|
||||
out << " return fieldIndices.value(name) - 1;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "QHash<QByteArray, int> " << name << "::createFieldIndices() {\n";
|
||||
out << " QHash<QByteArray, int> indices;\n";
|
||||
out << " int index = 0;\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " foreach (const MetaField& field, " << base << "::getMetaFields()) {\n";
|
||||
out << " indices.insert(field.getName(), index++);\n";
|
||||
out << " }\n";
|
||||
}
|
||||
out << " foreach (const MetaField& field, getMetaFields()) {\n";
|
||||
out << " indices.insert(field.getName(), index++);\n";
|
||||
out << " }\n";
|
||||
out << " return indices;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "void " << name << "::setField(int index, const QVariant& value) {\n";
|
||||
if (!str.clazz.bases.isEmpty()) {
|
||||
out << " int nextIndex;\n";
|
||||
}
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " if ((nextIndex = index - " << base << "::getFieldCount()) < 0) {\n";
|
||||
out << " " << base << "::setFieldValue(index, value);\n";
|
||||
out << " if ((nextIndex = index - " << base << "::getMetaFields().size()) < 0) {\n";
|
||||
out << " " << base << "::setField(index, value);\n";
|
||||
out << " return;\n";
|
||||
out << " }\n";
|
||||
out << " index = nextIndex;\n";
|
||||
|
|
Loading…
Reference in a new issue