Collection streaming (untested).

This commit is contained in:
Andrzej Kapolka 2014-03-18 11:46:12 -07:00
parent b84499c83b
commit a4cc15a2cd
2 changed files with 109 additions and 17 deletions

View file

@ -577,6 +577,22 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
if (_metadataType == NO_METADATA) {
return *this;
}
TypeStreamer::Category category = streamer->getCategory();
*this << (int)category;
switch (category) {
case TypeStreamer::SIMPLE_CATEGORY:
return *this;
case TypeStreamer::LIST_CATEGORY:
return *this << streamer->getValueStreamer();
case TypeStreamer::MAP_CATEGORY:
return *this << streamer->getKeyStreamer() << streamer->getValueStreamer();
default:
break; // fall through
}
// streamable type
const QVector<MetaField>& metaFields = streamer->getMetaFields();
*this << metaFields.size();
if (metaFields.isEmpty()) {
@ -612,6 +628,40 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
reader = TypeReader(typeName, streamer);
return *this;
}
int category;
*this >> category;
switch (category) {
case TypeStreamer::SIMPLE_CATEGORY:
reader = TypeReader(typeName, streamer);
return *this;
case TypeStreamer::LIST_CATEGORY: {
TypeReader valueReader;
*this >> valueReader;
if (streamer && streamer->getCategory() == TypeStreamer::LIST_CATEGORY &&
valueReader.matchesExactly(streamer->getValueStreamer())) {
reader = TypeReader(typeName, streamer);
} else {
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(),
TypeReaderPointer(new TypeReader(valueReader)));
}
return *this;
}
case TypeStreamer::MAP_CATEGORY: {
TypeReader keyReader, valueReader;
*this >> keyReader >> valueReader;
if (streamer && streamer->getCategory() == TypeStreamer::MAP_CATEGORY &&
keyReader.matchesExactly(streamer->getKeyStreamer()) &&
valueReader.matchesExactly(streamer->getValueStreamer())) {
reader = TypeReader(typeName, streamer);
} else {
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(new TypeReader(keyReader)),
TypeReaderPointer(new TypeReader(valueReader)));
}
return *this;
}
}
// streamable type
int fieldCount;
*this >> fieldCount;
QVector<FieldReader> fields(fieldCount);
@ -664,20 +714,20 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
// 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);
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(), TypeReaderPointer(), 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);
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(), TypeReaderPointer(), fields);
return *this;
}
}
reader = TypeReader(typeName, streamer);
return *this;
}
reader = TypeReader(typeName, streamer, false, fields);
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(), TypeReaderPointer(), fields);
return *this;
}
@ -773,11 +823,13 @@ QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObj
return propertyReaders;
}
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer,
bool exactMatch, const QVector<FieldReader>& fields) :
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch,
const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader, const QVector<FieldReader>& fields) :
_typeName(typeName),
_streamer(streamer),
_exactMatch(exactMatch),
_keyReader(keyReader),
_valueReader(valueReader),
_fields(fields) {
}
@ -786,8 +838,29 @@ QVariant TypeReader::read(Bitstream& in) const {
return _streamer->read(in);
}
QVariant object = _streamer ? QVariant(_streamer->getType(), 0) : QVariant();
foreach (const FieldReader& field, _fields) {
field.read(in, _streamer, object);
if (_valueReader) {
int size;
in >> size;
if (_keyReader) {
for (int i = 0; i < size; i++) {
QVariant key = _keyReader->read(in);
QVariant value = _valueReader->read(in);
if (_streamer) {
_streamer->insert(object, key, value);
}
}
} else {
for (int i = 0; i < size; i++) {
QVariant value = _valueReader->read(in);
if (_streamer) {
_streamer->insert(object, value);
}
}
}
} else {
foreach (const FieldReader& field, _fields) {
field.read(in, _streamer, object);
}
}
return object;
}
@ -866,6 +939,10 @@ void TypeStreamer::setField(int index, QVariant& object, const QVariant& value)
// nothing by default
}
TypeStreamer::Category TypeStreamer::getCategory() const {
return SIMPLE_CATEGORY;
}
const TypeStreamer* TypeStreamer::getKeyStreamer() const {
return NULL;
}
@ -874,7 +951,7 @@ const TypeStreamer* TypeStreamer::getValueStreamer() const {
return NULL;
}
void TypeStreamer::append(QVariant& object, const QVariant& element) const {
void TypeStreamer::insert(QVariant& object, const QVariant& element) const {
// nothing by default
}

View file

@ -444,12 +444,15 @@ template<class K, class V> inline Bitstream& Bitstream::operator>>(QHash<K, V>&
return *this;
}
typedef QSharedPointer<TypeReader> TypeReaderPointer;
/// 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>());
TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true,
const TypeReaderPointer& keyReader = TypeReaderPointer(), const TypeReaderPointer& valueReader = TypeReaderPointer(),
const QVector<FieldReader>& fields = QVector<FieldReader>());
const QByteArray& getTypeName() const { return _typeName; }
const TypeStreamer* getStreamer() const { return _streamer; }
@ -466,6 +469,8 @@ private:
QByteArray _typeName;
const TypeStreamer* _streamer;
bool _exactMatch;
TypeReaderPointer _keyReader;
TypeReaderPointer _valueReader;
QVector<FieldReader> _fields;
};
@ -552,8 +557,6 @@ Q_DECLARE_METATYPE(const QMetaObject*)
class TypeStreamer {
public:
enum Category { SIMPLE_CATEGORY, STREAMABLE_CATEGORY };
virtual ~TypeStreamer();
void setType(int type) { _type = type; }
@ -565,11 +568,15 @@ public:
virtual const QVector<MetaField>& getMetaFields() const;
virtual int getFieldIndex(const QByteArray& name) const;
virtual void setField(int index, QVariant& object, const QVariant& value) const;
enum Category { SIMPLE_CATEGORY, STREAMABLE_CATEGORY, LIST_CATEGORY, MAP_CATEGORY };
virtual Category getCategory() const;
virtual const TypeStreamer* getKeyStreamer() const;
virtual const TypeStreamer* getValueStreamer() const;
virtual void append(QVariant& object, const QVariant& element) const;
virtual void insert(QVariant& object, const QVariant& value) const;
virtual void insert(QVariant& object, const QVariant& key, const QVariant& value) const;
private:
@ -589,6 +596,7 @@ public:
template<class T> class StreamableTypeStreamer : public SimpleTypeStreamer<T> {
public:
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::STREAMABLE_CATEGORY; }
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 {
@ -603,22 +611,29 @@ template<class T> class CollectionTypeStreamer : public SimpleTypeStreamer<T> {
template<class T> class CollectionTypeStreamer<QList<T> > : public SimpleTypeStreamer<QList<T> > {
public:
virtual void append(QVariant& object, const QVariant& element) const {
static_cast<QList<T>*>(object.data())->append(element.value<T>()); }
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
virtual void insert(QVariant& object, const QVariant& value) const {
static_cast<QList<T>*>(object.data())->append(value.value<T>()); }
};
/// A streamer for set types.
template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > {
public:
virtual void append(QVariant& object, const QVariant& element) const {
static_cast<QSet<T>*>(object.data())->insert(element.value<T>()); }
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
virtual void insert(QVariant& object, const QVariant& value) const {
static_cast<QSet<T>*>(object.data())->insert(value.value<T>()); }
};
/// A streamer for hash types.
template<class K, class V> class CollectionTypeStreamer<QHash<K, V> > : public SimpleTypeStreamer<QHash<K, V> > {
public:
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::MAP_CATEGORY; }
virtual const TypeStreamer* getKeyStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<K>()); }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<V>()); }
virtual void insert(QVariant& object, const QVariant& key, const QVariant& value) const {
static_cast<QHash<K, V>*>(object.data())->insert(key.value<K>(), value.value<V>()); }
};