diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index f6e988a5f2..0708ede5b6 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -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& 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 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& 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 Bitstream::getPropertyReaders(const QMetaObject* metaObj return propertyReaders; } -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, - bool exactMatch, const QVector& fields) : +TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch, + const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader, const QVector& 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 } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 5d5c75857d..769ae4a250 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -444,12 +444,15 @@ template inline Bitstream& Bitstream::operator>>(QHash& return *this; } +typedef QSharedPointer 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& fields = QVector()); + TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true, + const TypeReaderPointer& keyReader = TypeReaderPointer(), const TypeReaderPointer& valueReader = TypeReaderPointer(), + const QVector& fields = QVector()); 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 _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& 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 StreamableTypeStreamer : public SimpleTypeStreamer { public: + virtual TypeStreamer::Category getCategory() const { return TypeStreamer::STREAMABLE_CATEGORY; } virtual const QVector& 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 CollectionTypeStreamer : public SimpleTypeStreamer { template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual void append(QVariant& object, const QVariant& element) const { - static_cast*>(object.data())->append(element.value()); } + virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; } + virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId()); } + virtual void insert(QVariant& object, const QVariant& value) const { + static_cast*>(object.data())->append(value.value()); } }; /// A streamer for set types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual void append(QVariant& object, const QVariant& element) const { - static_cast*>(object.data())->insert(element.value()); } + virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; } + virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId()); } + virtual void insert(QVariant& object, const QVariant& value) const { + static_cast*>(object.data())->insert(value.value()); } }; /// A streamer for hash types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: + virtual TypeStreamer::Category getCategory() const { return TypeStreamer::MAP_CATEGORY; } + virtual const TypeStreamer* getKeyStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId()); } + virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId()); } virtual void insert(QVariant& object, const QVariant& key, const QVariant& value) const { static_cast*>(object.data())->insert(key.value(), value.value()); } };