From 69899f4d37bfa28bf1f29f48a0bd3121d6a6a46b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 10 Jun 2014 16:53:00 -0700 Subject: [PATCH 01/11] Edging towards generic container types. --- libraries/metavoxels/src/Bitstream.cpp | 95 ++++++++++++++++++++++---- libraries/metavoxels/src/Bitstream.h | 68 +++++++++++++++--- 2 files changed, 140 insertions(+), 23 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index d7e15a9dd6..ca6cd5dd83 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -44,6 +44,9 @@ static int quatStreamer = Bitstream::registerTypeStreamer(qMetaTypeId static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); +static int genericValueStreamer = Bitstream::registerTypeStreamer( + qRegisterMetaType(), new GenericTypeStreamer()); + IDStreamer::IDStreamer(Bitstream& stream) : _stream(stream), _bits(1) { @@ -92,7 +95,10 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta } int Bitstream::registerTypeStreamer(int type, TypeStreamer* streamer) { - streamer->setType(type); + streamer->_type = type; + if (!streamer->_self) { + streamer->_self = TypeStreamerPointer(streamer); + } getTypeStreamers().insert(type, streamer); return 0; } @@ -109,12 +115,13 @@ QList Bitstream::getMetaObjectSubClasses(const QMetaObject* return getMetaObjectSubClasses().values(metaObject); } -Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, QObject* parent) : +Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, GenericsMode genericsMode, QObject* parent) : QObject(parent), _underlying(underlying), _byte(0), _position(0), _metadataType(metadataType), + _genericsMode(genericsMode), _metaObjectStreamer(*this), _typeStreamerStreamer(*this), _attributeStreamer(*this), @@ -751,7 +758,7 @@ Bitstream& Bitstream::operator<<(const QVariant& value) { } const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); if (streamer) { - _typeStreamerStreamer << streamer; + _typeStreamerStreamer << streamer->getStreamerToWrite(value); streamer->write(*this, value); } else { qWarning() << "Non-streamable type: " << value.typeName() << "\n"; @@ -793,6 +800,16 @@ Bitstream& Bitstream::operator>>(OwnedAttributeValue& attributeValue) { return *this; } +Bitstream& Bitstream::operator<<(const GenericValue& value) { + value.getStreamer()->write(*this, value.getValue()); + return *this; +} + +Bitstream& Bitstream::operator>>(GenericValue& value) { + value = GenericValue(); + return *this; +} + Bitstream& Bitstream::operator<<(const QObject* object) { if (!object) { _metaObjectStreamer << NULL; @@ -1232,20 +1249,26 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { streamer = getEnumStreamersByName().value(typeName); } } - if (!streamer) { - qWarning() << "Unknown type name: " << typeName << "\n"; - } if (_metadataType == NO_METADATA) { + if (!streamer) { + qWarning() << "Unknown type name:" << typeName; + } reader = TypeReader(typeName, streamer); return *this; } int type; *this >> type; + if (type == TypeReader::SIMPLE_TYPE) { + if (!streamer) { + qWarning() << "Unknown type name:" << typeName; + } + reader = TypeReader(typeName, streamer); + return *this; + } + if (_genericsMode == ALL_GENERICS) { + streamer = NULL; + } switch (type) { - case TypeReader::SIMPLE_TYPE: - reader = TypeReader(typeName, streamer); - return *this; - case TypeReader::ENUM_TYPE: { if (_metadataType == FULL_METADATA) { int keyCount; @@ -1910,6 +1933,38 @@ const char* TypeStreamer::getName() const { return QMetaType::typeName(_type); } +const TypeStreamer* TypeStreamer::getStreamerToWrite(const QVariant& value) const { + return this; +} + +bool TypeStreamer::equal(const QVariant& first, const QVariant& second) const { + return first == second; +} + +void TypeStreamer::write(Bitstream& out, const QVariant& value) const { + // nothing by default +} + +QVariant TypeStreamer::read(Bitstream& in) const { + return QVariant(); +} + +void TypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + // nothing by default +} + +void TypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + value = reference; +} + +void TypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + // nothing by default +} + +void TypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + value = reference; +} + void TypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) const { // nothing by default } @@ -1993,15 +2048,17 @@ EnumTypeStreamer::EnumTypeStreamer(const QMetaObject* metaObject, const char* na _name(QByteArray(metaObject->className()) + "::" + name), _bits(-1) { - setType(QMetaType::Int); + _type = QMetaType::Int; + _self = TypeStreamerPointer(this); } EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) : _name(QByteArray(metaEnum.scope()) + "::" + metaEnum.name()), _metaEnum(metaEnum), _bits(-1) { - - setType(QMetaType::Int); + + _type = QMetaType::Int; + _self = TypeStreamerPointer(this); } const char* EnumTypeStreamer::getName() const { @@ -2094,3 +2151,15 @@ void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash().getStreamer().data(); +} diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index d05f6574c0..dadfe52911 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -36,6 +36,7 @@ class Attribute; class AttributeValue; class Bitstream; class FieldReader; +class GenericValue; class ObjectReader; class OwnedAttributeValue; class PropertyReader; @@ -232,8 +233,17 @@ public: enum MetadataType { NO_METADATA, HASH_METADATA, FULL_METADATA }; + enum GenericsMode { NO_GENERICS, FALLBACK_GENERICS, ALL_GENERICS }; + /// Creates a new bitstream. Note: the stream may be used for reading or writing, but not both. - Bitstream(QDataStream& underlying, MetadataType metadataType = NO_METADATA, QObject* parent = NULL); + /// \param metadataType the metadata type, which determines the amount of version-resiliency: with no metadata, all types + /// must match exactly; with hash metadata, any types which do not match exactly will be ignored; with full metadata, + /// fields (and enum values, etc.) will be remapped by name + /// \param genericsMode the generics mode, which determines which types will be replaced by generic equivalents: with + /// no generics, no generics will be created; with fallback generics, generics will be created for any unknown types; with + /// all generics, generics will be created for all non-simple types + Bitstream(QDataStream& underlying, MetadataType metadataType = NO_METADATA, + GenericsMode = NO_GENERICS, QObject* parent = NULL); /// Substitutes the supplied metaobject for the given class name's default mapping. void addMetaObjectSubstitution(const QByteArray& className, const QMetaObject* metaObject); @@ -364,6 +374,9 @@ public: Bitstream& operator<<(const AttributeValue& attributeValue); Bitstream& operator>>(OwnedAttributeValue& attributeValue); + Bitstream& operator<<(const GenericValue& value); + Bitstream& operator>>(GenericValue& value); + template Bitstream& operator<<(const QList& list); template Bitstream& operator>>(QList& list); @@ -429,6 +442,7 @@ private: int _position; MetadataType _metadataType; + GenericsMode _genericsMode; RepeatedValueStreamer _metaObjectStreamer; RepeatedValueStreamer _typeStreamerStreamer; @@ -890,27 +904,32 @@ Q_DECLARE_METATYPE(const QMetaObject*) /// Macro for registering streamable meta-objects. #define REGISTER_META_OBJECT(x) static int x##Registration = Bitstream::registerMetaObject(#x, &x::staticMetaObject); +typedef QSharedPointer TypeStreamerPointer; + /// Interface for objects that can write values to and read values from bitstreams. class TypeStreamer { public: virtual ~TypeStreamer(); - void setType(int type) { _type = type; } int getType() const { return _type; } + const TypeStreamerPointer& getSelf() const { return _self; } + virtual const char* getName() const; - virtual bool equal(const QVariant& first, const QVariant& second) const = 0; + virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; - virtual void write(Bitstream& out, const QVariant& value) const = 0; - virtual QVariant read(Bitstream& in) const = 0; + virtual bool equal(const QVariant& first, const QVariant& second) const; + + virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; - virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const = 0; - virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const = 0; + virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; + virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; - virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const = 0; - virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const = 0; + virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; + virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; virtual void setEnumValue(QVariant& object, int value, const QHash& mappings) const; @@ -937,9 +956,12 @@ public: virtual QVariant getValue(const QVariant& object, int index) const; virtual void setValue(QVariant& object, int index, const QVariant& value) const; -private: +protected: + + friend class Bitstream; int _type; + TypeStreamerPointer _self; }; QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer); @@ -992,6 +1014,32 @@ private: int _bits; }; +/// Contains a value along with a pointer to its streamer. +class GenericValue { +public: + + GenericValue(const TypeStreamerPointer& streamer = TypeStreamerPointer(), const QVariant& value = QVariant()); + + const TypeStreamerPointer& getStreamer() const { return _streamer; } + const QVariant& getValue() const { return _value; } + + bool operator==(const GenericValue& other) const; + +private: + + TypeStreamerPointer _streamer; + QVariant _value; +}; + +Q_DECLARE_METATYPE(GenericValue) + +/// A streamer class for generic values. +class GenericTypeStreamer : public SimpleTypeStreamer { +public: + + virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; +}; + /// A streamer for types compiled by mtc. template class StreamableTypeStreamer : public SimpleTypeStreamer { public: From 9aa152f43ff01938c5b8e87105426541c2357ba3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 10 Jun 2014 18:29:21 -0700 Subject: [PATCH 02/11] More TypeReader refactoring progress. --- libraries/metavoxels/src/Bitstream.cpp | 157 ++++++++++++++++++++++++- libraries/metavoxels/src/Bitstream.h | 60 +++++++++- 2 files changed, 213 insertions(+), 4 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index ca6cd5dd83..83ec86013c 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -1950,11 +1950,22 @@ QVariant TypeStreamer::read(Bitstream& in) const { } void TypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { - // nothing by default + if (value == reference) { + out << false; + } else { + out << true; + writeRawDelta(out, value, reference); + } } void TypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { - value = reference; + bool changed; + in >> changed; + if (changed) { + readRawDelta(in, value, reference); + } else { + value = reference; + } } void TypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { @@ -2151,6 +2162,30 @@ void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) : + _baseStreamer(baseStreamer), + _bits(bits), + _mappings(mappings) { +} + +QVariant MappedEnumTypeStreamer::read(Bitstream& in) const { + QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + int value = 0; + in.read(&value, _bits); + if (_baseStreamer) { + _baseStreamer->setEnumValue(object, value, _mappings); + } + return object; +} + +void MappedEnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { + int value = 0; + in.read(&value, _bits); + if (_baseStreamer) { + _baseStreamer->setEnumValue(object, value, _mappings); + } +} + GenericValue::GenericValue(const TypeStreamerPointer& streamer, const QVariant& value) : _streamer(streamer), _value(value) { @@ -2163,3 +2198,121 @@ bool GenericValue::operator==(const GenericValue& other) const { const TypeStreamer* GenericTypeStreamer::getStreamerToWrite(const QVariant& value) const { return value.value().getStreamer().data(); } + +MappedListTypeStreamer::MappedListTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) : + _baseStreamer(baseStreamer), + _valueStreamer(valueStreamer) { +} + +QVariant MappedListTypeStreamer::read(Bitstream& in) const { + QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + int size; + in >> size; + for (int i = 0; i < size; i++) { + QVariant value = _valueStreamer->read(in); + if (_baseStreamer) { + _baseStreamer->insert(object, value); + } + } + return object; +} + +void MappedListTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { + object = reference; + int size, referenceSize; + in >> size >> referenceSize; + if (_baseStreamer) { + if (size < referenceSize) { + _baseStreamer->prune(object, size); + } + for (int i = 0; i < size; i++) { + if (i < referenceSize) { + QVariant value; + _valueStreamer->readDelta(in, value, _baseStreamer->getValue(reference, i)); + _baseStreamer->setValue(object, i, value); + } else { + _baseStreamer->insert(object, _valueStreamer->read(in)); + } + } + } else { + for (int i = 0; i < size; i++) { + if (i < referenceSize) { + QVariant value; + _valueStreamer->readDelta(in, value, QVariant()); + } else { + _valueStreamer->read(in); + } + } + } +} + +MappedSetTypeStreamer::MappedSetTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) : + MappedListTypeStreamer(baseStreamer, valueStreamer) { +} + +void MappedSetTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { + object = reference; + int addedOrRemoved; + in >> addedOrRemoved; + for (int i = 0; i < addedOrRemoved; i++) { + QVariant value = _valueStreamer->read(in); + if (_baseStreamer && !_baseStreamer->remove(object, value)) { + _baseStreamer->insert(object, value); + } + } +} + +MappedMapTypeStreamer::MappedMapTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& keyStreamer, + const TypeStreamerPointer& valueStreamer) : + _baseStreamer(baseStreamer), + _keyStreamer(keyStreamer), + _valueStreamer(valueStreamer) { +} + +QVariant MappedMapTypeStreamer::read(Bitstream& in) const { + QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + int size; + in >> size; + for (int i = 0; i < size; i++) { + QVariant key = _keyStreamer->read(in); + QVariant value = _valueStreamer->read(in); + if (_baseStreamer) { + _baseStreamer->insert(object, key, value); + } + } + return object; +} + +void MappedMapTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { + object = reference; + int added; + in >> added; + for (int i = 0; i < added; i++) { + QVariant key = _keyStreamer->read(in); + QVariant value = _valueStreamer->read(in); + if (_baseStreamer) { + _baseStreamer->insert(object, key, value); + } + } + int modified; + in >> modified; + for (int i = 0; i < modified; i++) { + QVariant key = _keyStreamer->read(in); + QVariant value; + if (_baseStreamer) { + _valueStreamer->readDelta(in, value, _baseStreamer->getValue(reference, key)); + _baseStreamer->insert(object, key, value); + } else { + _valueStreamer->readDelta(in, value, QVariant()); + } + } + int removed; + in >> removed; + for (int i = 0; i < removed; i++) { + QVariant key = _keyStreamer->read(in); + if (_baseStreamer) { + _baseStreamer->remove(object, key); + } + } +} + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index dadfe52911..cd7a0439aa 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -47,6 +47,7 @@ class TypeStreamer; typedef SharedObjectPointerTemplate AttributePointer; typedef QPair ScopeNamePair; +typedef QSharedPointer TypeStreamerPointer; typedef QVector PropertyReaderVector; typedef QVector PropertyWriterVector; @@ -904,8 +905,6 @@ Q_DECLARE_METATYPE(const QMetaObject*) /// Macro for registering streamable meta-objects. #define REGISTER_META_OBJECT(x) static int x##Registration = Bitstream::registerMetaObject(#x, &x::staticMetaObject); -typedef QSharedPointer TypeStreamerPointer; - /// Interface for objects that can write values to and read values from bitstreams. class TypeStreamer { public: @@ -1014,6 +1013,22 @@ private: int _bits; }; +/// A streamer class for enums that maps to a local type. +class MappedEnumTypeStreamer : public TypeStreamer { +public: + + MappedEnumTypeStreamer(const TypeStreamer* baseStreamer, int bits, const QHash& mappings); + + virtual QVariant read(Bitstream& in) const; + virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; + +private: + + const TypeStreamer* _baseStreamer; + int _bits; + QHash _mappings; +}; + /// Contains a value along with a pointer to its streamer. class GenericValue { public: @@ -1089,6 +1104,21 @@ public: static_cast*>(object.data())->replace(index, value.value()); } }; +/// A streamer for lists that maps to a local type. +class MappedListTypeStreamer : public TypeStreamer { +public: + + MappedListTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer); + + virtual QVariant read(Bitstream& in) const; + virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; + +protected: + + const TypeStreamer* _baseStreamer; + TypeStreamerPointer _valueStreamer; +}; + /// A streamer for set types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: @@ -1101,6 +1131,15 @@ public: return static_cast*>(object.data())->remove(key.value()); } }; +/// A streamer for sets that maps to a local type. +class MappedSetTypeStreamer : public MappedListTypeStreamer { +public: + + MappedSetTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer); + + virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; +}; + /// A streamer for hash types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: @@ -1116,6 +1155,23 @@ public: return QVariant::fromValue(static_cast*>(object.constData())->value(key.value())); } }; +/// A streamer for maps that maps to a local type. +class MappedMapTypeStreamer : public TypeStreamer { +public: + + MappedMapTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& keyStreamer, + const TypeStreamerPointer& valueStreamer); + + virtual QVariant read(Bitstream& in) const; + virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; + +private: + + const TypeStreamer* _baseStreamer; + TypeStreamerPointer _keyStreamer; + TypeStreamerPointer _valueStreamer; +}; + /// Macro for registering simple type streamers. #define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \ Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); From 6b48554fdd39d685bcffb56bbcaed94ffe4b3275 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Jun 2014 11:26:21 -0700 Subject: [PATCH 03/11] Added explanatory comment. --- libraries/metavoxels/src/ScriptCache.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/metavoxels/src/ScriptCache.cpp b/libraries/metavoxels/src/ScriptCache.cpp index 9648a047cb..ffd5200a2e 100644 --- a/libraries/metavoxels/src/ScriptCache.cpp +++ b/libraries/metavoxels/src/ScriptCache.cpp @@ -90,6 +90,7 @@ bool operator==(const QScriptValue& first, const QScriptValue& second) { return true; } else { + // if none of the above tests apply, first must be invalid return !second.isValid(); } } From a529bc7e28579c5663c03f70c6fdf1020d69e2b9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Jun 2014 13:40:12 -0700 Subject: [PATCH 04/11] Refactoring. --- libraries/metavoxels/src/Bitstream.cpp | 463 +++++++------------------ libraries/metavoxels/src/Bitstream.h | 117 ++----- 2 files changed, 157 insertions(+), 423 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 83ec86013c..ce46429393 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -301,9 +301,9 @@ void Bitstream::writeRawDelta(const QVariant& value, const QVariant& reference) } void Bitstream::readRawDelta(QVariant& value, const QVariant& reference) { - TypeReader typeReader; - _typeStreamerStreamer >> typeReader; - typeReader.readRawDelta(*this, value, reference); + TypeStreamerPointer typeStreamer; + _typeStreamerStreamer >> typeStreamer; + typeStreamer->readRawDelta(*this, value, reference); } void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) { @@ -767,12 +767,12 @@ Bitstream& Bitstream::operator<<(const QVariant& value) { } Bitstream& Bitstream::operator>>(QVariant& value) { - TypeReader reader; - _typeStreamerStreamer >> reader; - if (reader.getTypeName().isEmpty()) { + TypeStreamerPointer streamer; + _typeStreamerStreamer >> streamer; + if (!streamer) { value = QVariant(); } else { - value = reader.read(*this); + value = streamer->read(*this); } return *this; } @@ -853,14 +853,14 @@ Bitstream& Bitstream::operator<<(const TypeStreamer* streamer) { } Bitstream& Bitstream::operator>>(const TypeStreamer*& streamer) { - TypeReader typeReader; - _typeStreamerStreamer >> typeReader; - streamer = typeReader.getStreamer(); + TypeStreamerPointer typeStreamer; + _typeStreamerStreamer >> typeStreamer; + streamer = typeStreamer.data(); return *this; } -Bitstream& Bitstream::operator>>(TypeReader& reader) { - _typeStreamerStreamer >> reader; +Bitstream& Bitstream::operator>>(TypeStreamerPointer& streamer) { + _typeStreamerStreamer >> streamer; return *this; } @@ -1122,8 +1122,8 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { *this >> storedPropertyCount; PropertyReaderVector properties(storedPropertyCount); for (int i = 0; i < storedPropertyCount; i++) { - TypeReader typeReader; - *this >> typeReader; + TypeStreamerPointer typeStreamer; + *this >> typeStreamer; QMetaProperty property = QMetaProperty(); if (_metadataType == FULL_METADATA) { QByteArray propertyName; @@ -1132,7 +1132,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { property = metaObject->property(metaObject->indexOfProperty(propertyName)); } } - properties[i] = PropertyReader(typeReader, property); + properties[i] = PropertyReader(typeStreamer, 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) { @@ -1143,7 +1143,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { if (propertyWriters.size() == properties.size()) { for (int i = 0; i < propertyWriters.size(); i++) { const PropertyWriter& propertyWriter = propertyWriters.at(i); - if (!properties.at(i).getReader().matchesExactly(propertyWriter.getStreamer())) { + if (properties.at(i).getStreamer() != propertyWriter.getStreamer()) { matches = false; break; } @@ -1176,13 +1176,13 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { if (_metadataType == NO_METADATA) { return *this; } - TypeReader::Type type = streamer->getReaderType(); - *this << (int)type; - switch (type) { - case TypeReader::SIMPLE_TYPE: + TypeStreamer::Category category = streamer->getCategory(); + *this << (int)category; + switch (category) { + case TypeStreamer::SIMPLE_CATEGORY: return *this; - case TypeReader::ENUM_TYPE: { + case TypeStreamer::ENUM_CATEGORY: { QMetaEnum metaEnum = streamer->getMetaEnum(); if (_metadataType == FULL_METADATA) { *this << metaEnum.keyCount(); @@ -1203,11 +1203,11 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { } return *this; } - case TypeReader::LIST_TYPE: - case TypeReader::SET_TYPE: + case TypeStreamer::LIST_CATEGORY: + case TypeStreamer::SET_CATEGORY: return *this << streamer->getValueStreamer(); - case TypeReader::MAP_TYPE: + case TypeStreamer::MAP_CATEGORY: return *this << streamer->getKeyStreamer() << streamer->getValueStreamer(); default: @@ -1235,46 +1235,50 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { return *this; } -Bitstream& Bitstream::operator>(TypeReader& reader) { +Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { QByteArray typeName; *this >> typeName; if (typeName.isEmpty()) { - reader = TypeReader(); + streamer = TypeStreamerPointer(); return *this; } - const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); - if (!streamer) { - streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); - if (!streamer) { - streamer = getEnumStreamersByName().value(typeName); + const TypeStreamer* baseStreamer = _typeStreamerSubstitutions.value(typeName); + if (!baseStreamer) { + baseStreamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + if (!baseStreamer) { + baseStreamer = getEnumStreamersByName().value(typeName); } } + // start out with the base, if any + if (baseStreamer) { + streamer = baseStreamer->getSelf(); + } else { + streamer = TypeStreamerPointer(); + } if (_metadataType == NO_METADATA) { - if (!streamer) { + if (!baseStreamer) { qWarning() << "Unknown type name:" << typeName; } - reader = TypeReader(typeName, streamer); return *this; } - int type; - *this >> type; - if (type == TypeReader::SIMPLE_TYPE) { + int category; + *this >> category; + if (category == TypeStreamer::SIMPLE_CATEGORY) { if (!streamer) { qWarning() << "Unknown type name:" << typeName; } - reader = TypeReader(typeName, streamer); return *this; } if (_genericsMode == ALL_GENERICS) { - streamer = NULL; + baseStreamer = NULL; } - switch (type) { - case TypeReader::ENUM_TYPE: { + switch (category) { + case TypeStreamer::ENUM_CATEGORY: { if (_metadataType == FULL_METADATA) { int keyCount; *this >> keyCount; - QMetaEnum metaEnum = (streamer && streamer->getReaderType() == TypeReader::ENUM_TYPE) ? - streamer->getMetaEnum() : QMetaEnum(); + QMetaEnum metaEnum = (baseStreamer && baseStreamer->getCategory() == TypeStreamer::ENUM_CATEGORY) ? + baseStreamer->getMetaEnum() : QMetaEnum(); QHash mappings; bool matches = (keyCount == metaEnum.keyCount()); int highestValue = 0; @@ -1289,17 +1293,16 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { } matches &= (value == localValue); } - if (matches) { - reader = TypeReader(typeName, streamer); - } else { - reader = TypeReader(typeName, streamer, getBitsForHighestValue(highestValue), mappings); + if (!matches) { + streamer = TypeStreamerPointer(new MappedEnumTypeStreamer(baseStreamer, + getBitsForHighestValue(highestValue), mappings)); } } else { int bits; *this >> bits; QCryptographicHash hash(QCryptographicHash::Md5); - if (streamer && streamer->getReaderType() == TypeReader::ENUM_TYPE) { - QMetaEnum metaEnum = streamer->getMetaEnum(); + if (baseStreamer && baseStreamer->getCategory() == TypeStreamer::ENUM_CATEGORY) { + QMetaEnum metaEnum = baseStreamer->getMetaEnum(); for (int i = 0; i < metaEnum.keyCount(); i++) { hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1); qint32 value = metaEnum.value(i); @@ -1309,37 +1312,30 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray localHashResult = hash.result(); QByteArray remoteHashResult(localHashResult.size(), 0); read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); - if (localHashResult == remoteHashResult) { - reader = TypeReader(typeName, streamer); - } else { - reader = TypeReader(typeName, streamer, bits, QHash()); + if (localHashResult != remoteHashResult) { + streamer = TypeStreamerPointer(new MappedEnumTypeStreamer(baseStreamer, bits, QHash())); } } return *this; } - case TypeReader::LIST_TYPE: - case TypeReader::SET_TYPE: { - TypeReader valueReader; - *this >> valueReader; - if (streamer && streamer->getReaderType() == type && - valueReader.matchesExactly(streamer->getValueStreamer())) { - reader = TypeReader(typeName, streamer); - } else { - reader = TypeReader(typeName, streamer, (TypeReader::Type)type, - TypeReaderPointer(new TypeReader(valueReader))); + case TypeStreamer::LIST_CATEGORY: + case TypeStreamer::SET_CATEGORY: { + TypeStreamerPointer valueStreamer; + *this >> valueStreamer; + if (!(baseStreamer && baseStreamer->getCategory() == category && + valueStreamer == baseStreamer->getValueStreamer())) { + streamer = TypeStreamerPointer(category == TypeStreamer::LIST_CATEGORY ? + new MappedListTypeStreamer(baseStreamer, valueStreamer) : + new MappedSetTypeStreamer(baseStreamer, valueStreamer)); } return *this; } - case TypeReader::MAP_TYPE: { - TypeReader keyReader, valueReader; - *this >> keyReader >> valueReader; - if (streamer && streamer->getReaderType() == TypeReader::MAP_TYPE && - keyReader.matchesExactly(streamer->getKeyStreamer()) && - valueReader.matchesExactly(streamer->getValueStreamer())) { - reader = TypeReader(typeName, streamer); - } else { - reader = TypeReader(typeName, streamer, TypeReaderPointer(new TypeReader(keyReader)), - TypeReaderPointer(new TypeReader(valueReader))); + case TypeStreamer::MAP_CATEGORY: { + TypeStreamerPointer keyStreamer, valueStreamer; + *this >> keyStreamer >> valueStreamer; + if (!(baseStreamer && baseStreamer->getCategory() == TypeStreamer::MAP_CATEGORY && + keyStreamer == baseStreamer->getKeyStreamer() && valueStreamer == baseStreamer->getValueStreamer())) { + streamer = TypeStreamerPointer(new MappedMapTypeStreamer(baseStreamer, keyStreamer, valueStreamer)); } return *this; } @@ -1347,37 +1343,36 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { // streamable type int fieldCount; *this >> fieldCount; - QVector fields(fieldCount); + QVector fields(fieldCount); for (int i = 0; i < fieldCount; i++) { - TypeReader typeReader; - *this >> typeReader; + TypeStreamerPointer typeStreamer; + *this >> typeStreamer; int index = -1; if (_metadataType == FULL_METADATA) { QByteArray fieldName; *this >> fieldName; - if (streamer) { - index = streamer->getFieldIndex(fieldName); + if (baseStreamer) { + index = baseStreamer->getFieldIndex(fieldName); } } - fields[i] = FieldReader(typeReader, index); + fields[i] = StreamerIndexPair(typeStreamer, 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); bool matches = true; - if (streamer) { - const QVector& localFields = streamer->getMetaFields(); + if (baseStreamer) { + const QVector& localFields = baseStreamer->getMetaFields(); if (fieldCount != localFields.size()) { matches = false; } else { 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())) { + if (fields.at(i).first != localField.getStreamer()) { matches = false; break; } @@ -1388,29 +1383,27 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray localHashResult = hash.result(); QByteArray remoteHashResult(localHashResult.size(), 0); read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); - if (streamer && matches && localHashResult == remoteHashResult) { + if (baseStreamer && matches && localHashResult == remoteHashResult) { // since everything is the same, we can use the default streamer - reader = TypeReader(typeName, streamer); return *this; } - } else if (streamer) { + } else if (baseStreamer) { // 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(); + const QVector& localFields = baseStreamer->getMetaFields(); if (fieldCount != localFields.size()) { - reader = TypeReader(typeName, streamer, fields); + streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, 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, fields); + const StreamerIndexPair& field = fields.at(i); + if (field.first != localFields.at(i).getStreamer() || field.second != i) { + streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)); return *this; } } - reader = TypeReader(typeName, streamer); return *this; } - reader = TypeReader(typeName, streamer, fields); + streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)); return *this; } @@ -1575,7 +1568,7 @@ QHash Bitstream::createPropertyReaders streamer = getTypeStreamers().value(property.userType()); } if (streamer) { - readers.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); + readers.append(PropertyReader(streamer->getSelf(), property)); } } } @@ -1613,245 +1606,6 @@ QHash Bitstream::createPropertyWriters return propertyWriters; } -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) : - _typeName(typeName), - _streamer(streamer), - _exactMatch(true) { -} - -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, int bits, const QHash& mappings) : - _typeName(typeName), - _streamer(streamer), - _exactMatch(false), - _type(ENUM_TYPE), - _bits(bits), - _mappings(mappings) { -} - -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, const QVector& fields) : - _typeName(typeName), - _streamer(streamer), - _exactMatch(false), - _type(STREAMABLE_TYPE), - _fields(fields) { -} - -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, - Type type, const TypeReaderPointer& valueReader) : - _typeName(typeName), - _streamer(streamer), - _exactMatch(false), - _type(type), - _valueReader(valueReader) { -} - -TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, - const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader) : - _typeName(typeName), - _streamer(streamer), - _exactMatch(false), - _type(MAP_TYPE), - _keyReader(keyReader), - _valueReader(valueReader) { -} - -QVariant TypeReader::read(Bitstream& in) const { - if (_exactMatch) { - return _streamer->read(in); - } - QVariant object = _streamer ? QVariant(_streamer->getType(), 0) : QVariant(); - switch (_type) { - case ENUM_TYPE: { - int value = 0; - in.read(&value, _bits); - if (_streamer) { - _streamer->setEnumValue(object, value, _mappings); - } - break; - } - case STREAMABLE_TYPE: { - foreach (const FieldReader& field, _fields) { - field.read(in, _streamer, object); - } - break; - } - case LIST_TYPE: - case SET_TYPE: { - int size; - in >> size; - for (int i = 0; i < size; i++) { - QVariant value = _valueReader->read(in); - if (_streamer) { - _streamer->insert(object, value); - } - } - break; - } - case MAP_TYPE: { - int size; - in >> size; - for (int i = 0; i < size; i++) { - QVariant key = _keyReader->read(in); - QVariant value = _valueReader->read(in); - if (_streamer) { - _streamer->insert(object, key, value); - } - } - break; - } - default: - break; - } - return object; -} - -void TypeReader::readDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { - if (_exactMatch) { - _streamer->readDelta(in, object, reference); - return; - } - bool changed; - in >> changed; - if (changed) { - readRawDelta(in, object, reference); - } else { - object = reference; - } -} - -void TypeReader::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { - if (_exactMatch) { - _streamer->readRawDelta(in, object, reference); - return; - } - switch (_type) { - case ENUM_TYPE: { - int value = 0; - in.read(&value, _bits); - if (_streamer) { - _streamer->setEnumValue(object, value, _mappings); - } - break; - } - case STREAMABLE_TYPE: { - foreach (const FieldReader& field, _fields) { - field.readDelta(in, _streamer, object, reference); - } - break; - } - case LIST_TYPE: { - object = reference; - int size, referenceSize; - in >> size >> referenceSize; - if (_streamer) { - if (size < referenceSize) { - _streamer->prune(object, size); - } - for (int i = 0; i < size; i++) { - if (i < referenceSize) { - QVariant value; - _valueReader->readDelta(in, value, _streamer->getValue(reference, i)); - _streamer->setValue(object, i, value); - } else { - _streamer->insert(object, _valueReader->read(in)); - } - } - } else { - for (int i = 0; i < size; i++) { - if (i < referenceSize) { - QVariant value; - _valueReader->readDelta(in, value, QVariant()); - } else { - _valueReader->read(in); - } - } - } - break; - } - case SET_TYPE: { - object = reference; - int addedOrRemoved; - in >> addedOrRemoved; - for (int i = 0; i < addedOrRemoved; i++) { - QVariant value = _valueReader->read(in); - if (_streamer && !_streamer->remove(object, value)) { - _streamer->insert(object, value); - } - } - break; - } - case MAP_TYPE: { - object = reference; - int added; - in >> added; - for (int i = 0; i < added; i++) { - QVariant key = _keyReader->read(in); - QVariant value = _valueReader->read(in); - if (_streamer) { - _streamer->insert(object, key, value); - } - } - int modified; - in >> modified; - for (int i = 0; i < modified; i++) { - QVariant key = _keyReader->read(in); - QVariant value; - if (_streamer) { - _valueReader->readDelta(in, value, _streamer->getValue(reference, key)); - _streamer->insert(object, key, value); - } else { - _valueReader->readDelta(in, value, QVariant()); - } - } - int removed; - in >> removed; - for (int i = 0; i < removed; i++) { - QVariant key = _keyReader->read(in); - if (_streamer) { - _streamer->remove(object, key); - } - } - break; - } - default: - break; - } -} - -bool TypeReader::matchesExactly(const TypeStreamer* streamer) const { - return _exactMatch && _streamer == streamer; -} - -uint qHash(const TypeReader& typeReader, uint seed) { - return qHash(typeReader.getTypeName(), seed); -} - -QDebug& operator<<(QDebug& debug, const TypeReader& typeReader) { - return debug << typeReader.getTypeName(); -} - -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(object, _index, value); - } -} - -void FieldReader::readDelta(Bitstream& in, const TypeStreamer* streamer, QVariant& object, const QVariant& reference) const { - QVariant value; - if (_index != -1 && streamer) { - _reader.readDelta(in, value, streamer->getField(reference, _index)); - streamer->setField(object, _index, value); - } else { - _reader.readDelta(in, value, QVariant()); - } -} - ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject, const PropertyReaderVector& properties) : _className(className), @@ -1887,13 +1641,13 @@ QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader) { return debug << objectReader.getClassName(); } -PropertyReader::PropertyReader(const TypeReader& reader, const QMetaProperty& property) : - _reader(reader), +PropertyReader::PropertyReader(const TypeStreamerPointer& streamer, const QMetaProperty& property) : + _streamer(streamer), _property(property) { } void PropertyReader::read(Bitstream& in, QObject* object) const { - QVariant value = _reader.read(in); + QVariant value = _streamer->read(in); if (_property.isValid() && object) { _property.write(object, value); } @@ -1901,7 +1655,7 @@ void PropertyReader::read(Bitstream& in, QObject* object) const { void PropertyReader::readDelta(Bitstream& in, QObject* object, const QObject* reference) const { QVariant value; - _reader.readDelta(in, value, (_property.isValid() && reference) ? _property.read(reference) : QVariant()); + _streamer->readDelta(in, value, (_property.isValid() && reference) ? _property.read(reference) : QVariant()); if (_property.isValid() && object) { _property.write(object, value); } @@ -1997,8 +1751,8 @@ QVariant TypeStreamer::getField(const QVariant& object, int index) const { return QVariant(); } -TypeReader::Type TypeStreamer::getReaderType() const { - return TypeReader::SIMPLE_TYPE; +TypeStreamer::Category TypeStreamer::getCategory() const { + return SIMPLE_CATEGORY; } int TypeStreamer::getBits() const { @@ -2076,8 +1830,8 @@ const char* EnumTypeStreamer::getName() const { return _name.constData(); } -TypeReader::Type EnumTypeStreamer::getReaderType() const { - return TypeReader::ENUM_TYPE; +TypeStreamer::Category EnumTypeStreamer::getCategory() const { + return ENUM_CATEGORY; } int EnumTypeStreamer::getBits() const { @@ -2199,6 +1953,35 @@ const TypeStreamer* GenericTypeStreamer::getStreamerToWrite(const QVariant& valu return value.value().getStreamer().data(); } +MappedStreamableTypeStreamer::MappedStreamableTypeStreamer(const TypeStreamer* baseStreamer, + const QVector& fields) : + _baseStreamer(baseStreamer), + _fields(fields) { +} + +QVariant MappedStreamableTypeStreamer::read(Bitstream& in) const { + QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + foreach (const StreamerIndexPair& pair, _fields) { + QVariant value = pair.first->read(in); + if (pair.second != -1 && _baseStreamer) { + _baseStreamer->setField(object, pair.second, value); + } + } + return object; +} + +void MappedStreamableTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { + foreach (const StreamerIndexPair& pair, _fields) { + QVariant value; + if (pair.second != -1 && _baseStreamer) { + pair.first->readDelta(in, value, _baseStreamer->getField(reference, pair.second)); + _baseStreamer->setField(object, pair.second, value); + } else { + pair.first->readDelta(in, value, QVariant()); + } + } +} + MappedListTypeStreamer::MappedListTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) : _baseStreamer(baseStreamer), _valueStreamer(valueStreamer) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index cd7a0439aa..08b326d687 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -35,13 +35,11 @@ class QUrl; class Attribute; class AttributeValue; class Bitstream; -class FieldReader; class GenericValue; class ObjectReader; class OwnedAttributeValue; class PropertyReader; class PropertyWriter; -class TypeReader; class TypeStreamer; typedef SharedObjectPointerTemplate AttributePointer; @@ -209,7 +207,7 @@ public: class ReadMappings { public: QHash metaObjectValues; - QHash typeStreamerValues; + QHash typeStreamerValues; QHash attributeValues; QHash scriptStringValues; QHash sharedObjectValues; @@ -399,7 +397,7 @@ public: Bitstream& operator<<(const TypeStreamer* streamer); Bitstream& operator>>(const TypeStreamer*& streamer); - Bitstream& operator>>(TypeReader& reader); + Bitstream& operator>>(TypeStreamerPointer& streamer); Bitstream& operator<<(const AttributePointer& attribute); Bitstream& operator>>(AttributePointer& attribute); @@ -417,7 +415,7 @@ public: Bitstream& operator>(ObjectReader& objectReader); Bitstream& operator<(const TypeStreamer* streamer); - Bitstream& operator>(TypeReader& reader); + Bitstream& operator>(TypeStreamerPointer& reader); Bitstream& operator<(const AttributePointer& attribute); Bitstream& operator>(AttributePointer& attribute); @@ -446,7 +444,7 @@ private: GenericsMode _genericsMode; RepeatedValueStreamer _metaObjectStreamer; - RepeatedValueStreamer _typeStreamerStreamer; + RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; RepeatedValueStreamer _sharedObjectStreamer; @@ -756,73 +754,6 @@ 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: - - enum Type { SIMPLE_TYPE, ENUM_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; - - TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL); - - TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, int bits, const QHash& mappings); - - TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, const QVector& fields); - - TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, Type type, - const TypeReaderPointer& valueReader); - - TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, - const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader); - - const QByteArray& getTypeName() const { return _typeName; } - const TypeStreamer* getStreamer() const { return _streamer; } - - QVariant read(Bitstream& in) const; - void readDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; - void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) 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; - Type _type; - int _bits; - QHash _mappings; - TypeReaderPointer _keyReader; - TypeReaderPointer _valueReader; - QVector _fields; -}; - -uint qHash(const TypeReader& typeReader, uint seed = 0); - -QDebug& operator<<(QDebug& debug, const TypeReader& typeReader); - -/// 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; - void readDelta(Bitstream& in, const TypeStreamer* streamer, QVariant& object, const QVariant& reference) const; - -private: - - TypeReader _reader; - int _index; -}; - /// Contains the information required to read an object from the stream. class ObjectReader { public: @@ -854,16 +785,17 @@ QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader); class PropertyReader { public: - PropertyReader(const TypeReader& reader = TypeReader(), const QMetaProperty& property = QMetaProperty()); + PropertyReader(const TypeStreamerPointer& streamer = TypeStreamerPointer(), + const QMetaProperty& property = QMetaProperty()); - const TypeReader& getReader() const { return _reader; } + const TypeStreamerPointer& getStreamer() const { return _streamer; } void read(Bitstream& in, QObject* object) const; void readDelta(Bitstream& in, QObject* object, const QObject* reference) const; private: - TypeReader _reader; + TypeStreamerPointer _streamer; QMetaProperty _property; }; @@ -909,6 +841,8 @@ Q_DECLARE_METATYPE(const QMetaObject*) class TypeStreamer { public: + enum Category { SIMPLE_CATEGORY, ENUM_CATEGORY, STREAMABLE_CATEGORY, LIST_CATEGORY, SET_CATEGORY, MAP_CATEGORY }; + virtual ~TypeStreamer(); int getType() const { return _type; } @@ -937,7 +871,7 @@ public: virtual void setField(QVariant& object, int index, const QVariant& value) const; virtual QVariant getField(const QVariant& object, int index) const; - virtual TypeReader::Type getReaderType() const; + virtual Category getCategory() const; virtual int getBits() const; virtual QMetaEnum getMetaEnum() const; @@ -992,7 +926,7 @@ public: EnumTypeStreamer(const QMetaEnum& metaEnum); virtual const char* getName() const; - virtual TypeReader::Type getReaderType() const; + virtual Category getCategory() const; virtual int getBits() const; virtual QMetaEnum getMetaEnum() const; virtual bool equal(const QVariant& first, const QVariant& second) const; @@ -1059,7 +993,7 @@ public: template class StreamableTypeStreamer : public SimpleTypeStreamer { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::STREAMABLE_TYPE; } + 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(QVariant& object, int index, const QVariant& value) const { @@ -1068,6 +1002,23 @@ public: return static_cast(object.constData())->getField(index); } }; +typedef QPair StreamerIndexPair; + +/// A streamer class for streamables that maps to a local type. +class MappedStreamableTypeStreamer : public TypeStreamer { +public: + + MappedStreamableTypeStreamer(const TypeStreamer* baseStreamer, const QVector& fields); + + virtual QVariant read(Bitstream& in) const; + virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; + +private: + + const TypeStreamer* _baseStreamer; + QVector _fields; +}; + /// Base template for collection streamers. template class CollectionTypeStreamer : public SimpleTypeStreamer { }; @@ -1076,7 +1027,7 @@ template class CollectionTypeStreamer : public SimpleTypeStreamer { template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; } + 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()); } @@ -1092,7 +1043,7 @@ public: template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; } + 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()); } @@ -1123,7 +1074,7 @@ protected: template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::SET_TYPE; } + virtual TypeStreamer::Category getCategory() const { return TypeStreamer::SET_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()); } @@ -1144,7 +1095,7 @@ public: template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::MAP_TYPE; } + 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 { From c045595ccbbb6228ca5287751c06198be41d0037 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Jun 2014 14:25:45 -0700 Subject: [PATCH 05/11] More progress on refactoring. --- libraries/metavoxels/src/Bitstream.cpp | 93 +++++++++++--------------- libraries/metavoxels/src/Bitstream.h | 3 + 2 files changed, 42 insertions(+), 54 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index ce46429393..a6d5967fd3 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -1269,8 +1269,8 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { } return *this; } - if (_genericsMode == ALL_GENERICS) { - baseStreamer = NULL; + if (!baseStreamer) { + baseStreamer = getInvalidTypeStreamer(); } switch (category) { case TypeStreamer::ENUM_CATEGORY: { @@ -1544,6 +1544,18 @@ QHash Bitstream::createEnumStreamersByName() { return enumStreamersByName; } +const TypeStreamer* Bitstream::getInvalidTypeStreamer() { + const TypeStreamer* streamer = createInvalidTypeStreamer(); + return streamer; +} + +const TypeStreamer* Bitstream::createInvalidTypeStreamer() { + TypeStreamer* streamer = new TypeStreamer(); + streamer->_type = QMetaType::UnknownType; + streamer->_self = TypeStreamerPointer(streamer); + return streamer; +} + const QHash& Bitstream::getPropertyReaders() { static QHash propertyReaders = createPropertyReaders(); return propertyReaders; @@ -1923,21 +1935,17 @@ MappedEnumTypeStreamer::MappedEnumTypeStreamer(const TypeStreamer* baseStreamer, } QVariant MappedEnumTypeStreamer::read(Bitstream& in) const { - QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + QVariant object = QVariant(_baseStreamer->getType(), 0); int value = 0; in.read(&value, _bits); - if (_baseStreamer) { - _baseStreamer->setEnumValue(object, value, _mappings); - } + _baseStreamer->setEnumValue(object, value, _mappings); return object; } void MappedEnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { int value = 0; in.read(&value, _bits); - if (_baseStreamer) { - _baseStreamer->setEnumValue(object, value, _mappings); - } + _baseStreamer->setEnumValue(object, value, _mappings); } GenericValue::GenericValue(const TypeStreamerPointer& streamer, const QVariant& value) : @@ -1960,10 +1968,10 @@ MappedStreamableTypeStreamer::MappedStreamableTypeStreamer(const TypeStreamer* b } QVariant MappedStreamableTypeStreamer::read(Bitstream& in) const { - QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + QVariant object = QVariant(_baseStreamer->getType(), 0); foreach (const StreamerIndexPair& pair, _fields) { QVariant value = pair.first->read(in); - if (pair.second != -1 && _baseStreamer) { + if (pair.second != -1) { _baseStreamer->setField(object, pair.second, value); } } @@ -1973,7 +1981,7 @@ QVariant MappedStreamableTypeStreamer::read(Bitstream& in) const { void MappedStreamableTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { foreach (const StreamerIndexPair& pair, _fields) { QVariant value; - if (pair.second != -1 && _baseStreamer) { + if (pair.second != -1) { pair.first->readDelta(in, value, _baseStreamer->getField(reference, pair.second)); _baseStreamer->setField(object, pair.second, value); } else { @@ -1988,14 +1996,12 @@ MappedListTypeStreamer::MappedListTypeStreamer(const TypeStreamer* baseStreamer, } QVariant MappedListTypeStreamer::read(Bitstream& in) const { - QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + QVariant object = QVariant(_baseStreamer->getType(), 0); int size; in >> size; for (int i = 0; i < size; i++) { QVariant value = _valueStreamer->read(in); - if (_baseStreamer) { - _baseStreamer->insert(object, value); - } + _baseStreamer->insert(object, value); } return object; } @@ -2004,27 +2010,16 @@ void MappedListTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const object = reference; int size, referenceSize; in >> size >> referenceSize; - if (_baseStreamer) { - if (size < referenceSize) { - _baseStreamer->prune(object, size); - } - for (int i = 0; i < size; i++) { - if (i < referenceSize) { - QVariant value; - _valueStreamer->readDelta(in, value, _baseStreamer->getValue(reference, i)); - _baseStreamer->setValue(object, i, value); - } else { - _baseStreamer->insert(object, _valueStreamer->read(in)); - } - } - } else { - for (int i = 0; i < size; i++) { - if (i < referenceSize) { - QVariant value; - _valueStreamer->readDelta(in, value, QVariant()); - } else { - _valueStreamer->read(in); - } + if (size < referenceSize) { + _baseStreamer->prune(object, size); + } + for (int i = 0; i < size; i++) { + if (i < referenceSize) { + QVariant value; + _valueStreamer->readDelta(in, value, _baseStreamer->getValue(reference, i)); + _baseStreamer->setValue(object, i, value); + } else { + _baseStreamer->insert(object, _valueStreamer->read(in)); } } } @@ -2039,7 +2034,7 @@ void MappedSetTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const in >> addedOrRemoved; for (int i = 0; i < addedOrRemoved; i++) { QVariant value = _valueStreamer->read(in); - if (_baseStreamer && !_baseStreamer->remove(object, value)) { + if (!_baseStreamer->remove(object, value)) { _baseStreamer->insert(object, value); } } @@ -2053,15 +2048,13 @@ MappedMapTypeStreamer::MappedMapTypeStreamer(const TypeStreamer* baseStreamer, c } QVariant MappedMapTypeStreamer::read(Bitstream& in) const { - QVariant object = _baseStreamer ? QVariant(_baseStreamer->getType(), 0) : QVariant(); + QVariant object = QVariant(_baseStreamer->getType(), 0); int size; in >> size; for (int i = 0; i < size; i++) { QVariant key = _keyStreamer->read(in); QVariant value = _valueStreamer->read(in); - if (_baseStreamer) { - _baseStreamer->insert(object, key, value); - } + _baseStreamer->insert(object, key, value); } return object; } @@ -2073,29 +2066,21 @@ void MappedMapTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const for (int i = 0; i < added; i++) { QVariant key = _keyStreamer->read(in); QVariant value = _valueStreamer->read(in); - if (_baseStreamer) { - _baseStreamer->insert(object, key, value); - } + _baseStreamer->insert(object, key, value); } int modified; in >> modified; for (int i = 0; i < modified; i++) { QVariant key = _keyStreamer->read(in); QVariant value; - if (_baseStreamer) { - _valueStreamer->readDelta(in, value, _baseStreamer->getValue(reference, key)); - _baseStreamer->insert(object, key, value); - } else { - _valueStreamer->readDelta(in, value, QVariant()); - } + _valueStreamer->readDelta(in, value, _baseStreamer->getValue(reference, key)); + _baseStreamer->insert(object, key, value); } int removed; in >> removed; for (int i = 0; i < removed; i++) { QVariant key = _keyStreamer->read(in); - if (_baseStreamer) { - _baseStreamer->remove(object, key); - } + _baseStreamer->remove(object, key); } } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 08b326d687..434b14ce69 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -466,6 +466,9 @@ private: static const QHash& getEnumStreamersByName(); static QHash createEnumStreamersByName(); + static const TypeStreamer* getInvalidTypeStreamer(); + static const TypeStreamer* createInvalidTypeStreamer(); + static const QHash& getPropertyReaders(); static QHash createPropertyReaders(); From 6260d661f32d4645a631a332ea482f6086ca50ed Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Jun 2014 16:54:35 -0700 Subject: [PATCH 06/11] More work on generic containers. --- libraries/metavoxels/src/Bitstream.cpp | 259 +++++++++++++++++++------ libraries/metavoxels/src/Bitstream.h | 104 +++++++++- 2 files changed, 301 insertions(+), 62 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index a6d5967fd3..336cd36521 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -45,7 +45,9 @@ static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId()); static int genericValueStreamer = Bitstream::registerTypeStreamer( - qRegisterMetaType(), new GenericTypeStreamer()); + qRegisterMetaType(), new GenericValueStreamer()); + +static int qVariantPairListMetaTypeId = qRegisterMetaType(); IDStreamer::IDStreamer(Bitstream& stream) : _stream(stream), @@ -1173,65 +1175,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { } const char* typeName = streamer->getName(); *this << QByteArray::fromRawData(typeName, strlen(typeName)); - if (_metadataType == NO_METADATA) { - return *this; - } - TypeStreamer::Category category = streamer->getCategory(); - *this << (int)category; - switch (category) { - case TypeStreamer::SIMPLE_CATEGORY: - return *this; - - case TypeStreamer::ENUM_CATEGORY: { - QMetaEnum metaEnum = streamer->getMetaEnum(); - if (_metadataType == FULL_METADATA) { - *this << metaEnum.keyCount(); - for (int i = 0; i < metaEnum.keyCount(); i++) { - *this << QByteArray::fromRawData(metaEnum.key(i), strlen(metaEnum.key(i))); - *this << metaEnum.value(i); - } - } else { - *this << streamer->getBits(); - QCryptographicHash hash(QCryptographicHash::Md5); - for (int i = 0; i < metaEnum.keyCount(); i++) { - hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1); - qint32 value = metaEnum.value(i); - hash.addData((const char*)&value, sizeof(qint32)); - } - QByteArray hashResult = hash.result(); - write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE); - } - return *this; - } - case TypeStreamer::LIST_CATEGORY: - case TypeStreamer::SET_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()) { - 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); - } + if (_metadataType != NO_METADATA) { + *this << (int)streamer->getCategory(); + streamer->writeMetadata(*this, _metadataType == FULL_METADATA); + } return *this; } @@ -1703,6 +1650,31 @@ const TypeStreamer* TypeStreamer::getStreamerToWrite(const QVariant& value) cons return this; } +void TypeStreamer::writeMetadata(Bitstream& out, bool full) const { + if (getCategory() != STREAMABLE_CATEGORY) { + return; + } + // streamable type + const QVector& metaFields = getMetaFields(); + out << metaFields.size(); + if (metaFields.isEmpty()) { + return; + } + QCryptographicHash hash(QCryptographicHash::Md5); + foreach (const MetaField& metaField, metaFields) { + out << metaField.getStreamer(); + if (full) { + out << metaField.getName(); + } else { + hash.addData(metaField.getName().constData(), metaField.getName().size() + 1); + } + } + if (!full) { + QByteArray hashResult = hash.result(); + out.write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE); + } +} + bool TypeStreamer::equal(const QVariant& first, const QVariant& second) const { return first == second; } @@ -1842,6 +1814,27 @@ const char* EnumTypeStreamer::getName() const { return _name.constData(); } +void EnumTypeStreamer::writeMetadata(Bitstream& out, bool full) const { + QMetaEnum metaEnum = getMetaEnum(); + if (full) { + out << metaEnum.keyCount(); + for (int i = 0; i < metaEnum.keyCount(); i++) { + out << QByteArray::fromRawData(metaEnum.key(i), strlen(metaEnum.key(i))); + out << metaEnum.value(i); + } + } else { + out << getBits(); + QCryptographicHash hash(QCryptographicHash::Md5); + for (int i = 0; i < metaEnum.keyCount(); i++) { + hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1); + qint32 value = metaEnum.value(i); + hash.addData((const char*)&value, sizeof(qint32)); + } + QByteArray hashResult = hash.result(); + out.write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE); + } +} + TypeStreamer::Category EnumTypeStreamer::getCategory() const { return ENUM_CATEGORY; } @@ -1948,6 +1941,54 @@ void MappedEnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const _baseStreamer->setEnumValue(object, value, _mappings); } +GenericTypeStreamer::GenericTypeStreamer(const QByteArray& name) : + _name(name) { +} + +const char* GenericTypeStreamer::getName() const { + return _name.constData(); +} + +GenericEnumTypeStreamer::GenericEnumTypeStreamer(const QByteArray& name, const QVector& values, + int bits, const QByteArray& hash) : + GenericTypeStreamer(name), + _values(values), + _bits(bits), + _hash(hash) { + + _type = qMetaTypeId(); +} + +void GenericEnumTypeStreamer::writeMetadata(Bitstream& out, bool full) const { + if (full) { + out << _values.size(); + foreach (const NameIntPair& value, _values) { + out << value.first << value.second; + } + } else { + out << _bits; + if (_hash.isEmpty()) { + QCryptographicHash hash(QCryptographicHash::Md5); + foreach (const NameIntPair& value, _values) { + hash.addData(value.first.constData(), value.first.size() + 1); + qint32 intValue = value.second; + hash.addData((const char*)&intValue, sizeof(qint32)); + } + const_cast(this)->_hash = hash.result(); + } + out.write(_hash.constData(), _hash.size() * BITS_IN_BYTE); + } +} + +void GenericEnumTypeStreamer::write(Bitstream& out, const QVariant& value) const { + int intValue = value.toInt(); + out.write(&intValue, _bits); +} + +TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const { + return ENUM_CATEGORY; +} + GenericValue::GenericValue(const TypeStreamerPointer& streamer, const QVariant& value) : _streamer(streamer), _value(value) { @@ -1957,7 +1998,7 @@ bool GenericValue::operator==(const GenericValue& other) const { return _streamer == other._streamer && _value == other._value; } -const TypeStreamer* GenericTypeStreamer::getStreamerToWrite(const QVariant& value) const { +const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const { return value.value().getStreamer().data(); } @@ -1990,6 +2031,46 @@ void MappedStreamableTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, } } +GenericStreamableTypeStreamer::GenericStreamableTypeStreamer(const QByteArray& name, + const QVector& fields, const QByteArray& hash) : + GenericTypeStreamer(name), + _fields(fields), + _hash(hash) { + + _type = qMetaTypeId(); +} + +void GenericStreamableTypeStreamer::writeMetadata(Bitstream& out, bool full) const { + out << _fields.size(); + foreach (const StreamerNamePair& field, _fields) { + out << field.first.data(); + if (full) { + out << field.second; + } + } + if (!full) { + if (_hash.isEmpty()) { + QCryptographicHash hash(QCryptographicHash::Md5); + foreach (const StreamerNamePair& field, _fields) { + hash.addData(field.second.constData(), field.second.size() + 1); + } + const_cast(this)->_hash = hash.result(); + } + out.write(_hash.constData(), _hash.size() * BITS_IN_BYTE); + } +} + +void GenericStreamableTypeStreamer::write(Bitstream& out, const QVariant& value) const { + QVariantList values = value.toList(); + for (int i = 0; i < _fields.size(); i++) { + _fields.at(i).first->write(out, values.at(i)); + } +} + +TypeStreamer::Category GenericStreamableTypeStreamer::getCategory() const { + return STREAMABLE_CATEGORY; +} + MappedListTypeStreamer::MappedListTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) : _baseStreamer(baseStreamer), _valueStreamer(valueStreamer) { @@ -2024,6 +2105,29 @@ void MappedListTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const } } +GenericListTypeStreamer::GenericListTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer) : + GenericTypeStreamer(name), + _valueStreamer(valueStreamer) { + + _type = qMetaTypeId(); +} + +void GenericListTypeStreamer::writeMetadata(Bitstream& out, bool full) const { + out << _valueStreamer.data(); +} + +void GenericListTypeStreamer::write(Bitstream& out, const QVariant& value) const { + QVariantList values = value.toList(); + out << values.size(); + foreach (const QVariant& element, values) { + _valueStreamer->write(out, element); + } +} + +TypeStreamer::Category GenericListTypeStreamer::getCategory() const { + return LIST_CATEGORY; +} + MappedSetTypeStreamer::MappedSetTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) : MappedListTypeStreamer(baseStreamer, valueStreamer) { } @@ -2040,6 +2144,14 @@ void MappedSetTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const } } +GenericSetTypeStreamer::GenericSetTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer) : + GenericListTypeStreamer(name, valueStreamer) { +} + +TypeStreamer::Category GenericSetTypeStreamer::getCategory() const { + return SET_CATEGORY; +} + MappedMapTypeStreamer::MappedMapTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& keyStreamer, const TypeStreamerPointer& valueStreamer) : _baseStreamer(baseStreamer), @@ -2084,3 +2196,28 @@ void MappedMapTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const } } +GenericMapTypeStreamer::GenericMapTypeStreamer(const QByteArray& name, const TypeStreamerPointer& keyStreamer, + const TypeStreamerPointer& valueStreamer) : + GenericTypeStreamer(name), + _keyStreamer(keyStreamer), + _valueStreamer(valueStreamer) { + + _type = qMetaTypeId(); +} + +void GenericMapTypeStreamer::writeMetadata(Bitstream& out, bool full) const { + out << _keyStreamer.data() << _valueStreamer.data(); +} + +void GenericMapTypeStreamer::write(Bitstream& out, const QVariant& value) const { + QVariantPairList values = value.value(); + out << values.size(); + foreach (const QVariantPair& pair, values) { + _keyStreamer->write(out, pair.first); + _valueStreamer->write(out, pair.second); + } +} + +TypeStreamer::Category GenericMapTypeStreamer::getCategory() const { + return MAP_CATEGORY; +} diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 434b14ce69..6a3fa88c94 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -45,10 +45,16 @@ class TypeStreamer; typedef SharedObjectPointerTemplate AttributePointer; typedef QPair ScopeNamePair; +typedef QPair NameIntPair; typedef QSharedPointer TypeStreamerPointer; typedef QVector PropertyReaderVector; typedef QVector PropertyWriterVector; +typedef QPair QVariantPair; +typedef QList QVariantPairList; + +Q_DECLARE_METATYPE(QVariantPairList) + /// Streams integer identifiers that conform to the following pattern: each ID encountered in the stream is either one that /// has been sent (received) before, or is one more than the highest previously encountered ID (starting at zero). This allows /// us to use the minimum number of bits to encode the IDs. @@ -856,6 +862,8 @@ public: virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual bool equal(const QVariant& first, const QVariant& second) const; virtual void write(Bitstream& out, const QVariant& value) const; @@ -929,6 +937,7 @@ public: EnumTypeStreamer(const QMetaEnum& metaEnum); virtual const char* getName() const; + virtual void writeMetadata(Bitstream& out, bool full) const; virtual Category getCategory() const; virtual int getBits() const; virtual QMetaEnum getMetaEnum() const; @@ -966,6 +975,36 @@ private: QHash _mappings; }; +/// Base class for generic type streamers, which contain all the metadata required to write out a type. +class GenericTypeStreamer : public TypeStreamer { +public: + + GenericTypeStreamer(const QByteArray& name); + + virtual const char* getName() const; + +private: + + QByteArray _name; +}; + +/// A streamer for generic enums. +class GenericEnumTypeStreamer : public GenericTypeStreamer { +public: + + GenericEnumTypeStreamer(const QByteArray& name, const QVector& values, int bits, const QByteArray& hash); + + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual void write(Bitstream& out, const QVariant& value) const; + virtual Category getCategory() const; + +private: + + QVector _values; + int _bits; + QByteArray _hash; +}; + /// Contains a value along with a pointer to its streamer. class GenericValue { public: @@ -986,7 +1025,7 @@ private: Q_DECLARE_METATYPE(GenericValue) /// A streamer class for generic values. -class GenericTypeStreamer : public SimpleTypeStreamer { +class GenericValueStreamer : public SimpleTypeStreamer { public: virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; @@ -1022,6 +1061,24 @@ private: QVector _fields; }; +typedef QPair StreamerNamePair; + +/// A streamer for generic enums. +class GenericStreamableTypeStreamer : public GenericTypeStreamer { +public: + + GenericStreamableTypeStreamer(const QByteArray& name, const QVector& fields, const QByteArray& hash); + + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual void write(Bitstream& out, const QVariant& value) const; + virtual Category getCategory() const; + +private: + + QVector _fields; + QByteArray _hash; +}; + /// Base template for collection streamers. template class CollectionTypeStreamer : public SimpleTypeStreamer { }; @@ -1030,6 +1087,7 @@ template class CollectionTypeStreamer : public SimpleTypeStreamer { template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: + virtual void writeMetadata(Bitstream& out, bool full) const { out << getValueStreamer(); } 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 { @@ -1046,6 +1104,7 @@ public: template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: + virtual void writeMetadata(Bitstream& out, bool full) const { out << getValueStreamer(); } 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 { @@ -1073,10 +1132,26 @@ protected: TypeStreamerPointer _valueStreamer; }; +/// A streamer for generic lists. +class GenericListTypeStreamer : public GenericTypeStreamer { +public: + + GenericListTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer); + + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual void write(Bitstream& out, const QVariant& value) const; + virtual Category getCategory() const; + +private: + + TypeStreamerPointer _valueStreamer; +}; + /// A streamer for set types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: + virtual void writeMetadata(Bitstream& out, bool full) const { out << getValueStreamer(); } virtual TypeStreamer::Category getCategory() const { return TypeStreamer::SET_CATEGORY; } virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId()); } virtual void insert(QVariant& object, const QVariant& value) const { @@ -1094,10 +1169,20 @@ public: virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; }; +/// A streamer for generic sets. +class GenericSetTypeStreamer : public GenericListTypeStreamer { +public: + + GenericSetTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer); + + virtual Category getCategory() const; +}; + /// A streamer for hash types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: + virtual void writeMetadata(Bitstream& out, bool full) const { out << getKeyStreamer() << getValueStreamer(); } 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()); } @@ -1126,6 +1211,23 @@ private: TypeStreamerPointer _valueStreamer; }; +/// A streamer for generic maps. +class GenericMapTypeStreamer : public GenericTypeStreamer { +public: + + GenericMapTypeStreamer(const QByteArray& name, const TypeStreamerPointer& keyStreamer, + const TypeStreamerPointer& valueStreamer); + + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual void write(Bitstream& out, const QVariant& value) const; + virtual Category getCategory() const; + +private: + + TypeStreamerPointer _keyStreamer; + TypeStreamerPointer _valueStreamer; +}; + /// Macro for registering simple type streamers. #define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \ Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); From 6c98248e507cc6a29a35bce8c7176b1351bd0ff8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 11 Jun 2014 18:30:01 -0700 Subject: [PATCH 07/11] More progress on generics. --- libraries/metavoxels/src/Bitstream.cpp | 193 ++++++++++++++++++++----- libraries/metavoxels/src/Bitstream.h | 12 +- 2 files changed, 164 insertions(+), 41 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 336cd36521..d285e4aa3f 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -1216,7 +1216,15 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { } return *this; } + if (_genericsMode == ALL_GENERICS) { + streamer = readGenericTypeStreamer(typeName, category); + return *this; + } if (!baseStreamer) { + if (_genericsMode == FALLBACK_GENERICS) { + streamer = readGenericTypeStreamer(typeName, category); + return *this; + } baseStreamer = getInvalidTypeStreamer(); } switch (category) { @@ -1224,8 +1232,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { if (_metadataType == FULL_METADATA) { int keyCount; *this >> keyCount; - QMetaEnum metaEnum = (baseStreamer && baseStreamer->getCategory() == TypeStreamer::ENUM_CATEGORY) ? - baseStreamer->getMetaEnum() : QMetaEnum(); + QMetaEnum metaEnum = baseStreamer->getMetaEnum(); QHash mappings; bool matches = (keyCount == metaEnum.keyCount()); int highestValue = 0; @@ -1248,7 +1255,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { int bits; *this >> bits; QCryptographicHash hash(QCryptographicHash::Md5); - if (baseStreamer && baseStreamer->getCategory() == TypeStreamer::ENUM_CATEGORY) { + if (baseStreamer->getCategory() == TypeStreamer::ENUM_CATEGORY) { QMetaEnum metaEnum = baseStreamer->getMetaEnum(); for (int i = 0; i < metaEnum.keyCount(); i++) { hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1); @@ -1269,8 +1276,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { case TypeStreamer::SET_CATEGORY: { TypeStreamerPointer valueStreamer; *this >> valueStreamer; - if (!(baseStreamer && baseStreamer->getCategory() == category && - valueStreamer == baseStreamer->getValueStreamer())) { + if (!(baseStreamer->getCategory() == category && valueStreamer == baseStreamer->getValueStreamer())) { streamer = TypeStreamerPointer(category == TypeStreamer::LIST_CATEGORY ? new MappedListTypeStreamer(baseStreamer, valueStreamer) : new MappedSetTypeStreamer(baseStreamer, valueStreamer)); @@ -1280,7 +1286,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { case TypeStreamer::MAP_CATEGORY: { TypeStreamerPointer keyStreamer, valueStreamer; *this >> keyStreamer >> valueStreamer; - if (!(baseStreamer && baseStreamer->getCategory() == TypeStreamer::MAP_CATEGORY && + if (!(baseStreamer->getCategory() == TypeStreamer::MAP_CATEGORY && keyStreamer == baseStreamer->getKeyStreamer() && valueStreamer == baseStreamer->getValueStreamer())) { streamer = TypeStreamerPointer(new MappedMapTypeStreamer(baseStreamer, keyStreamer, valueStreamer)); } @@ -1298,9 +1304,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { if (_metadataType == FULL_METADATA) { QByteArray fieldName; *this >> fieldName; - if (baseStreamer) { - index = baseStreamer->getFieldIndex(fieldName); - } + index = baseStreamer->getFieldIndex(fieldName); } fields[i] = StreamerIndexPair(typeStreamer, index); } @@ -1308,49 +1312,44 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { if (_metadataType == HASH_METADATA) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; - if (baseStreamer) { - const QVector& localFields = baseStreamer->getMetaFields(); - if (fieldCount != localFields.size()) { - matches = false; - - } else { - if (fieldCount == 0) { - return *this; - } - for (int i = 0; i < fieldCount; i++) { - const MetaField& localField = localFields.at(i); - if (fields.at(i).first != localField.getStreamer()) { - matches = false; - break; - } - hash.addData(localField.getName().constData(), localField.getName().size() + 1); - } + const QVector& localFields = baseStreamer->getMetaFields(); + if (fieldCount != localFields.size()) { + matches = false; + + } else { + if (fieldCount == 0) { + return *this; } + for (int i = 0; i < fieldCount; i++) { + const MetaField& localField = localFields.at(i); + if (fields.at(i).first != localField.getStreamer()) { + matches = false; + break; + } + 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 (baseStreamer && matches && localHashResult == remoteHashResult) { + if (matches && localHashResult == remoteHashResult) { // since everything is the same, we can use the default streamer return *this; } - } else if (baseStreamer) { - // if all fields are the same type and in the right order, we can use the (more efficient) default streamer - const QVector& localFields = baseStreamer->getMetaFields(); - if (fieldCount != localFields.size()) { + } + // if all fields are the same type and in the right order, we can use the (more efficient) default streamer + const QVector& localFields = baseStreamer->getMetaFields(); + if (fieldCount != localFields.size()) { + streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)); + return *this; + } + for (int i = 0; i < fieldCount; i++) { + const StreamerIndexPair& field = fields.at(i); + if (field.first != localFields.at(i).getStreamer() || field.second != i) { streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)); return *this; } - for (int i = 0; i < fieldCount; i++) { - const StreamerIndexPair& field = fields.at(i); - if (field.first != localFields.at(i).getStreamer() || field.second != i) { - streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)); - return *this; - } - } - return *this; } - streamer = TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)); return *this; } @@ -1444,6 +1443,81 @@ void Bitstream::clearSharedObject(QObject* object) { } } +const int MD5_HASH_SIZE = 16; + +TypeStreamerPointer Bitstream::readGenericTypeStreamer(const QByteArray& name, int category) { + TypeStreamerPointer streamer; + switch (category) { + case TypeStreamer::ENUM_CATEGORY: { + QVector values; + int bits; + QByteArray hash; + if (_metadataType == FULL_METADATA) { + int keyCount; + *this >> keyCount; + values.resize(keyCount); + int highestValue = 0; + for (int i = 0; i < keyCount; i++) { + QByteArray name; + int value; + *this >> name >> value; + values[i] = NameIntPair(name, value); + highestValue = qMax(highestValue, value); + } + bits = getBitsForHighestValue(highestValue); + + } else { + *this >> bits; + hash.resize(MD5_HASH_SIZE); + read(hash.data(), hash.size() * BITS_IN_BYTE); + } + streamer = TypeStreamerPointer(new GenericEnumTypeStreamer(name, values, bits, hash)); + break; + } + case TypeStreamer::STREAMABLE_CATEGORY: { + int fieldCount; + *this >> fieldCount; + QVector fields(fieldCount); + QByteArray hash; + if (fieldCount == 0) { + streamer = TypeStreamerPointer(new GenericStreamableTypeStreamer(name, fields, hash)); + break; + } + for (int i = 0; i < fieldCount; i++) { + TypeStreamerPointer streamer; + *this >> streamer; + QByteArray name; + if (_metadataType == FULL_METADATA) { + *this >> name; + } + fields[i] = StreamerNamePair(streamer, name); + } + if (_metadataType == HASH_METADATA) { + hash.resize(MD5_HASH_SIZE); + read(hash.data(), hash.size() * BITS_IN_BYTE); + } + streamer = TypeStreamerPointer(new GenericStreamableTypeStreamer(name, fields, hash)); + break; + } + case TypeStreamer::LIST_CATEGORY: + case TypeStreamer::SET_CATEGORY: { + TypeStreamerPointer valueStreamer; + *this >> valueStreamer; + streamer = TypeStreamerPointer(category == TypeStreamer::LIST_CATEGORY ? + new GenericListTypeStreamer(name, valueStreamer) : new GenericSetTypeStreamer(name, valueStreamer)); + break; + } + case TypeStreamer::MAP_CATEGORY: { + TypeStreamerPointer keyStreamer, valueStreamer; + *this >> keyStreamer >> valueStreamer; + streamer = TypeStreamerPointer(new GenericMapTypeStreamer(name, keyStreamer, valueStreamer)); + break; + } + } + static_cast(streamer.data())->_weakSelf = streamer; + return streamer; +} + QHash& Bitstream::getMetaObjects() { static QHash metaObjects; return metaObjects; @@ -1985,6 +2059,12 @@ void GenericEnumTypeStreamer::write(Bitstream& out, const QVariant& value) const out.write(&intValue, _bits); } +QVariant GenericEnumTypeStreamer::read(Bitstream& in) const { + int intValue = 0; + in.read(&intValue, _bits); + return QVariant::fromValue(GenericValue(_weakSelf, intValue)); +} + TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const { return ENUM_CATEGORY; } @@ -2042,6 +2122,9 @@ GenericStreamableTypeStreamer::GenericStreamableTypeStreamer(const QByteArray& n void GenericStreamableTypeStreamer::writeMetadata(Bitstream& out, bool full) const { out << _fields.size(); + if (_fields.isEmpty()) { + return; + } foreach (const StreamerNamePair& field, _fields) { out << field.first.data(); if (full) { @@ -2067,6 +2150,14 @@ void GenericStreamableTypeStreamer::write(Bitstream& out, const QVariant& value) } } +QVariant GenericStreamableTypeStreamer::read(Bitstream& in) const { + QVariantList values; + foreach (const StreamerNamePair& field, _fields) { + values.append(field.first->read(in)); + } + return QVariant::fromValue(GenericValue(_weakSelf, values)); +} + TypeStreamer::Category GenericStreamableTypeStreamer::getCategory() const { return STREAMABLE_CATEGORY; } @@ -2124,6 +2215,16 @@ void GenericListTypeStreamer::write(Bitstream& out, const QVariant& value) const } } +QVariant GenericListTypeStreamer::read(Bitstream& in) const { + QVariantList values; + int size; + in >> size; + for (int i = 0; i < size; i++) { + values.append(_valueStreamer->read(in)); + } + return QVariant::fromValue(GenericValue(_weakSelf, values)); +} + TypeStreamer::Category GenericListTypeStreamer::getCategory() const { return LIST_CATEGORY; } @@ -2218,6 +2319,18 @@ void GenericMapTypeStreamer::write(Bitstream& out, const QVariant& value) const } } +QVariant GenericMapTypeStreamer::read(Bitstream& in) const { + QVariantPairList values; + int size; + in >> size; + for (int i = 0; i < size; i++) { + QVariant key = _keyStreamer->read(in); + QVariant value = _valueStreamer->read(in); + values.append(QVariantPair(key, value)); + } + return QVariant::fromValue(GenericValue(_weakSelf, QVariant::fromValue(values))); +} + TypeStreamer::Category GenericMapTypeStreamer::getCategory() const { return MAP_CATEGORY; } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 6a3fa88c94..ee9b8b472c 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -47,6 +47,7 @@ typedef SharedObjectPointerTemplate AttributePointer; typedef QPair ScopeNamePair; typedef QPair NameIntPair; typedef QSharedPointer TypeStreamerPointer; +typedef QWeakPointer WeakTypeStreamerPointer; typedef QVector PropertyReaderVector; typedef QVector PropertyWriterVector; @@ -442,6 +443,8 @@ private slots: private: + TypeStreamerPointer readGenericTypeStreamer(const QByteArray& name, int category); + QDataStream& _underlying; quint8 _byte; int _position; @@ -983,9 +986,12 @@ public: virtual const char* getName() const; -private: +protected: + + friend class Bitstream; QByteArray _name; + WeakTypeStreamerPointer _weakSelf; }; /// A streamer for generic enums. @@ -996,6 +1002,7 @@ public: virtual void writeMetadata(Bitstream& out, bool full) const; virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; virtual Category getCategory() const; private: @@ -1071,6 +1078,7 @@ public: virtual void writeMetadata(Bitstream& out, bool full) const; virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; virtual Category getCategory() const; private: @@ -1140,6 +1148,7 @@ public: virtual void writeMetadata(Bitstream& out, bool full) const; virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; virtual Category getCategory() const; private: @@ -1220,6 +1229,7 @@ public: virtual void writeMetadata(Bitstream& out, bool full) const; virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; virtual Category getCategory() const; private: From b4bd774789a310a6570ee025e4f454542775e47b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 12 Jun 2014 16:22:32 -0700 Subject: [PATCH 08/11] Midpoint on generic object streaming. --- libraries/metavoxels/src/Bitstream.cpp | 177 +++++++++++++++++++++++-- libraries/metavoxels/src/Bitstream.h | 138 +++++++++++++++---- 2 files changed, 274 insertions(+), 41 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index d285e4aa3f..f1c927451b 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -1639,6 +1639,153 @@ QHash Bitstream::createPropertyWriters return propertyWriters; } +MappedObjectStreamer::MappedObjectStreamer(const QVector& properties) : + _properties(properties) { +} + +const char* MappedObjectStreamer::getName() const { + return _metaObject->className(); +} + +void MappedObjectStreamer::writeMetadata(Bitstream& out, bool full) const { + out << _properties.size(); + if (_properties.isEmpty()) { + return; + } + QCryptographicHash hash(QCryptographicHash::Md5); + foreach (const StreamerPropertyPair& property, _properties) { + out << property.first.data(); + if (full) { + out << QByteArray::fromRawData(property.second.name(), strlen(property.second.name())); + } else { + hash.addData(property.second.name(), strlen(property.second.name()) + 1); + } + } + if (!full) { + QByteArray hashResult = hash.result(); + out.write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE); + } +} + +void MappedObjectStreamer::write(Bitstream& out, QObject* object) const { + foreach (const StreamerPropertyPair& property, _properties) { + property.first->write(out, property.second.read(object)); + } +} + +void MappedObjectStreamer::writeDelta(Bitstream& out, QObject* object, QObject* reference) const { + foreach (const StreamerPropertyPair& property, _properties) { + property.first->writeDelta(out, property.second.read(object), (reference && reference->metaObject() == _metaObject) ? + property.second.read(reference) : QVariant()); + } +} + +QObject* MappedObjectStreamer::read(Bitstream& in, QObject* object) const { + if (!object && _metaObject) { + object = _metaObject->newInstance(); + } + foreach (const StreamerPropertyPair& property, _properties) { + QVariant value = property.first->read(in); + if (property.second.isValid() && object) { + property.second.write(object, value); + } + } + return object; +} + +QObject* MappedObjectStreamer::readDelta(Bitstream& in, const QObject* reference, QObject* object) const { + if (!object && _metaObject) { + object = _metaObject->newInstance(); + } + foreach (const StreamerPropertyPair& property, _properties) { + QVariant value; + property.first->readDelta(in, value, (property.second.isValid() && reference) ? + property.second.read(reference) : QVariant()); + if (property.second.isValid() && object) { + property.second.write(object, value); + } + } + return object; +} + +GenericObjectStreamer::GenericObjectStreamer(const QByteArray& name, const QVector& properties, + const QByteArray& hash) : + _name(name), + _properties(properties), + _hash(hash) { + + _metaObject = &GenericSharedObject::staticMetaObject; +} + +const char* GenericObjectStreamer::getName() const { + return _name.constData(); +} + +void GenericObjectStreamer::writeMetadata(Bitstream& out, bool full) const { + out << _properties.size(); + if (_properties.isEmpty()) { + return; + } + foreach (const StreamerNamePair& property, _properties) { + out << property.first.data(); + if (full) { + out << property.second; + } + } + if (!full) { + if (_hash.isEmpty()) { + QCryptographicHash hash(QCryptographicHash::Md5); + foreach (const StreamerNamePair& property, _properties) { + hash.addData(property.second.constData(), property.second.size() + 1); + } + const_cast(this)->_hash = hash.result(); + } + out.write(_hash.constData(), _hash.size() * BITS_IN_BYTE); + } +} + +void GenericObjectStreamer::write(Bitstream& out, QObject* object) const { + const QVariantList& values = static_cast(object)->getValues(); + for (int i = 0; i < _properties.size(); i++) { + _properties.at(i).first->write(out, values.at(i)); + } +} + +void GenericObjectStreamer::writeDelta(Bitstream& out, QObject* object, QObject* reference) const { + for (int i = 0; i < _properties.size(); i++) { + _properties.at(i).first->writeDelta(out, static_cast(object)->getValues().at(i), reference ? + static_cast(reference)->getValues().at(i) : QVariant()); + } +} + +QObject* GenericObjectStreamer::read(Bitstream& in, QObject* object) const { + if (!object) { + object = new GenericSharedObject(_weakSelf); + } + QVariantList values; + foreach (const StreamerNamePair& property, _properties) { + values.append(property.first->read(in)); + } + static_cast(object)->setValues(values); + return object; +} + +QObject* GenericObjectStreamer::readDelta(Bitstream& in, const QObject* reference, QObject* object) const { + if (!object) { + object = new GenericSharedObject(_weakSelf); + } + QVariantList values; + for (int i = 0; i < _properties.size(); i++) { + const StreamerNamePair& property = _properties.at(i); + QVariant value; + property.first->readDelta(in, value, reference ? + static_cast(reference)->getValues().at(i) : QVariant()); + values.append(value); + } + static_cast(object)->setValues(values); + return object; +} + ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject, const PropertyReaderVector& properties) : _className(className), @@ -1713,6 +1860,19 @@ MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) : _streamer(streamer) { } +GenericValue::GenericValue(const TypeStreamerPointer& streamer, const QVariant& value) : + _streamer(streamer), + _value(value) { +} + +bool GenericValue::operator==(const GenericValue& other) const { + return _streamer == other._streamer && _value == other._value; +} + +GenericSharedObject::GenericSharedObject(const ObjectStreamerPointer& streamer) : + _streamer(streamer) { +} + TypeStreamer::~TypeStreamer() { } @@ -2069,19 +2229,6 @@ TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const { return ENUM_CATEGORY; } -GenericValue::GenericValue(const TypeStreamerPointer& streamer, const QVariant& value) : - _streamer(streamer), - _value(value) { -} - -bool GenericValue::operator==(const GenericValue& other) const { - return _streamer == other._streamer && _value == other._value; -} - -const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const { - return value.value().getStreamer().data(); -} - MappedStreamableTypeStreamer::MappedStreamableTypeStreamer(const TypeStreamer* baseStreamer, const QVector& fields) : _baseStreamer(baseStreamer), @@ -2334,3 +2481,7 @@ QVariant GenericMapTypeStreamer::read(Bitstream& in) const { TypeStreamer::Category GenericMapTypeStreamer::getCategory() const { return MAP_CATEGORY; } + +const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const { + return value.value().getStreamer().data(); +} diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index ee9b8b472c..07e4b94568 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -37,6 +37,7 @@ class AttributeValue; class Bitstream; class GenericValue; class ObjectReader; +class ObjectStreamer; class OwnedAttributeValue; class PropertyReader; class PropertyWriter; @@ -46,6 +47,8 @@ typedef SharedObjectPointerTemplate AttributePointer; typedef QPair ScopeNamePair; typedef QPair NameIntPair; +typedef QSharedPointer ObjectStreamerPointer; +typedef QWeakPointer WeakObjectStreamerPointer; typedef QSharedPointer TypeStreamerPointer; typedef QWeakPointer WeakTypeStreamerPointer; typedef QVector PropertyReaderVector; @@ -766,6 +769,68 @@ template inline Bitstream& Bitstream::operator>>(QHash& return *this; } +/// Contains the information required to stream an object. +class ObjectStreamer { +public: + + virtual const char* getName() const = 0; + virtual void writeMetadata(Bitstream& out, bool full) const = 0; + virtual void write(Bitstream& out, QObject* object) const = 0; + virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const = 0; + virtual QObject* read(Bitstream& in, QObject* object = NULL) const = 0; + virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const = 0; + +protected: + + const QMetaObject* _metaObject; + ObjectStreamerPointer _self; +}; + +typedef QPair StreamerPropertyPair; + +/// A streamer that maps to a local class. +class MappedObjectStreamer : public ObjectStreamer { +public: + + MappedObjectStreamer(const QVector& properties); + + virtual const char* getName() const; + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual void write(Bitstream& out, QObject* object) const; + virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const; + virtual QObject* read(Bitstream& in, QObject* object = NULL) const; + virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; + +private: + + QVector _properties; +}; + +typedef QPair StreamerNamePair; + +/// A streamer for generic objects. +class GenericObjectStreamer : public ObjectStreamer { +public: + + GenericObjectStreamer(const QByteArray& name, const QVector& properties, const QByteArray& hash); + + virtual const char* getName() const; + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual void write(Bitstream& out, QObject* object) const; + virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const; + virtual QObject* read(Bitstream& in, QObject* object = NULL) const; + virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; + +private: + + friend class Bitstream; + + QByteArray _name; + WeakObjectStreamerPointer _weakSelf; + QVector _properties; + QByteArray _hash; +}; + /// Contains the information required to read an object from the stream. class ObjectReader { public: @@ -849,6 +914,44 @@ Q_DECLARE_METATYPE(const QMetaObject*) /// Macro for registering streamable meta-objects. #define REGISTER_META_OBJECT(x) static int x##Registration = Bitstream::registerMetaObject(#x, &x::staticMetaObject); +/// Contains a value along with a pointer to its streamer. +class GenericValue { +public: + + GenericValue(const TypeStreamerPointer& streamer = TypeStreamerPointer(), const QVariant& value = QVariant()); + + const TypeStreamerPointer& getStreamer() const { return _streamer; } + const QVariant& getValue() const { return _value; } + + bool operator==(const GenericValue& other) const; + +private: + + TypeStreamerPointer _streamer; + QVariant _value; +}; + +Q_DECLARE_METATYPE(GenericValue) + +/// Contains a list of property values along with a pointer to their metadata. +class GenericSharedObject : public SharedObject { + Q_OBJECT + +public: + + GenericSharedObject(const ObjectStreamerPointer& streamer); + + const ObjectStreamerPointer& getStreamer() const { return _streamer; } + + void setValues(const QVariantList& values) { _values = values; } + const QVariantList& getValues() const { return _values; } + +private: + + ObjectStreamerPointer _streamer; + QVariantList _values; +}; + /// Interface for objects that can write values to and read values from bitstreams. class TypeStreamer { public: @@ -1012,32 +1115,6 @@ private: QByteArray _hash; }; -/// Contains a value along with a pointer to its streamer. -class GenericValue { -public: - - GenericValue(const TypeStreamerPointer& streamer = TypeStreamerPointer(), const QVariant& value = QVariant()); - - const TypeStreamerPointer& getStreamer() const { return _streamer; } - const QVariant& getValue() const { return _value; } - - bool operator==(const GenericValue& other) const; - -private: - - TypeStreamerPointer _streamer; - QVariant _value; -}; - -Q_DECLARE_METATYPE(GenericValue) - -/// A streamer class for generic values. -class GenericValueStreamer : public SimpleTypeStreamer { -public: - - virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; -}; - /// A streamer for types compiled by mtc. template class StreamableTypeStreamer : public SimpleTypeStreamer { public: @@ -1068,8 +1145,6 @@ private: QVector _fields; }; -typedef QPair StreamerNamePair; - /// A streamer for generic enums. class GenericStreamableTypeStreamer : public GenericTypeStreamer { public: @@ -1238,6 +1313,13 @@ private: TypeStreamerPointer _valueStreamer; }; +/// A streamer class for generic values. +class GenericValueStreamer : public SimpleTypeStreamer { +public: + + virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; +}; + /// Macro for registering simple type streamers. #define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \ Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); From 9e151001e032ac78ef796e3318e3942bb527d3fc Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 12 Jun 2014 18:47:18 -0700 Subject: [PATCH 09/11] More object streaming refactory. --- libraries/metavoxels/src/Bitstream.cpp | 392 ++++++++++++------------- libraries/metavoxels/src/Bitstream.h | 129 +++----- 2 files changed, 216 insertions(+), 305 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index f1c927451b..760b1fc646 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -124,7 +124,7 @@ Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, Generic _position(0), _metadataType(metadataType), _genericsMode(genericsMode), - _metaObjectStreamer(*this), + _objectStreamerStreamer(*this), _typeStreamerStreamer(*this), _attributeStreamer(*this), _scriptStringStreamer(*this), @@ -198,7 +198,7 @@ void Bitstream::reset() { } Bitstream::WriteMappings Bitstream::getAndResetWriteMappings() { - WriteMappings mappings = { _metaObjectStreamer.getAndResetTransientOffsets(), + WriteMappings mappings = { _objectStreamerStreamer.getAndResetTransientOffsets(), _typeStreamerStreamer.getAndResetTransientOffsets(), _attributeStreamer.getAndResetTransientOffsets(), _scriptStringStreamer.getAndResetTransientOffsets(), @@ -207,7 +207,7 @@ Bitstream::WriteMappings Bitstream::getAndResetWriteMappings() { } void Bitstream::persistWriteMappings(const WriteMappings& mappings) { - _metaObjectStreamer.persistTransientOffsets(mappings.metaObjectOffsets); + _objectStreamerStreamer.persistTransientOffsets(mappings.objectStreamerOffsets); _typeStreamerStreamer.persistTransientOffsets(mappings.typeStreamerOffsets); _attributeStreamer.persistTransientOffsets(mappings.attributeOffsets); _scriptStringStreamer.persistTransientOffsets(mappings.scriptStringOffsets); @@ -235,7 +235,7 @@ void Bitstream::persistAndResetWriteMappings() { } Bitstream::ReadMappings Bitstream::getAndResetReadMappings() { - ReadMappings mappings = { _metaObjectStreamer.getAndResetTransientValues(), + ReadMappings mappings = { _objectStreamerStreamer.getAndResetTransientValues(), _typeStreamerStreamer.getAndResetTransientValues(), _attributeStreamer.getAndResetTransientValues(), _scriptStringStreamer.getAndResetTransientValues(), @@ -244,7 +244,7 @@ Bitstream::ReadMappings Bitstream::getAndResetReadMappings() { } void Bitstream::persistReadMappings(const ReadMappings& mappings) { - _metaObjectStreamer.persistTransientValues(mappings.metaObjectValues); + _objectStreamerStreamer.persistTransientValues(mappings.objectStreamerValues); _typeStreamerStreamer.persistTransientValues(mappings.typeStreamerValues); _attributeStreamer.persistTransientValues(mappings.attributeValues); _scriptStringStreamer.persistTransientValues(mappings.scriptStringValues); @@ -310,20 +310,20 @@ void Bitstream::readRawDelta(QVariant& value, const QVariant& reference) { void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) { if (!value) { - _metaObjectStreamer << NULL; + _objectStreamerStreamer << NULL; return; } const QMetaObject* metaObject = value->metaObject(); - _metaObjectStreamer << metaObject; - foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) { - propertyWriter.writeDelta(*this, value, reference); - } + const ObjectStreamer* streamer = (metaObject == &GenericSharedObject::staticMetaObject) ? + static_cast(value)->getStreamer().data() : getObjectStreamers().value(metaObject); + _objectStreamerStreamer << streamer; + streamer->writeRawDelta(*this, value, reference); } void Bitstream::readRawDelta(QObject*& value, const QObject* reference) { - ObjectReader objectReader; - _metaObjectStreamer >> objectReader; - value = objectReader.readDelta(*this, reference); + ObjectStreamerPointer streamer; + _objectStreamerStreamer >> streamer; + value = streamer ? streamer->readRawDelta(*this, reference) : NULL; } void Bitstream::writeRawDelta(const QScriptValue& value, const QScriptValue& reference) { @@ -814,38 +814,50 @@ Bitstream& Bitstream::operator>>(GenericValue& value) { Bitstream& Bitstream::operator<<(const QObject* object) { if (!object) { - _metaObjectStreamer << NULL; + _objectStreamerStreamer << NULL; return *this; } const QMetaObject* metaObject = object->metaObject(); - _metaObjectStreamer << metaObject; - foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) { - propertyWriter.write(*this, object); - } + const ObjectStreamer* streamer = (metaObject == &GenericSharedObject::staticMetaObject) ? + static_cast(object)->getStreamer().data() : getObjectStreamers().value(metaObject); + _objectStreamerStreamer << streamer; + streamer->write(*this, object); return *this; } Bitstream& Bitstream::operator>>(QObject*& object) { - ObjectReader objectReader; - _metaObjectStreamer >> objectReader; - object = objectReader.read(*this); + ObjectStreamerPointer streamer; + _objectStreamerStreamer >> streamer; + object = streamer ? streamer->read(*this) : NULL; return *this; } Bitstream& Bitstream::operator<<(const QMetaObject* metaObject) { - _metaObjectStreamer << metaObject; + _objectStreamerStreamer << getObjectStreamers().value(metaObject); return *this; } Bitstream& Bitstream::operator>>(const QMetaObject*& metaObject) { - ObjectReader objectReader; - _metaObjectStreamer >> objectReader; - metaObject = objectReader.getMetaObject(); + ObjectStreamerPointer streamer; + _objectStreamerStreamer >> streamer; + metaObject = streamer->getMetaObject(); return *this; } -Bitstream& Bitstream::operator>>(ObjectReader& objectReader) { - _metaObjectStreamer >> objectReader; +Bitstream& Bitstream::operator<<(const ObjectStreamer* streamer) { + _objectStreamerStreamer << streamer; + return *this; +} + +Bitstream& Bitstream::operator>>(const ObjectStreamer*& streamer) { + ObjectStreamerPointer objectStreamer; + _objectStreamerStreamer >> objectStreamer; + streamer = objectStreamer.data(); + return *this; +} + +Bitstream& Bitstream::operator>>(ObjectStreamerPointer& streamer) { + _objectStreamerStreamer >> streamer; return *this; } @@ -1075,55 +1087,53 @@ Bitstream& Bitstream::operator>>(SharedObjectPointer& object) { return *this; } -Bitstream& Bitstream::operator<(const QMetaObject* metaObject) { - if (!metaObject) { +Bitstream& Bitstream::operator<(const ObjectStreamer* streamer) { + if (!streamer) { return *this << QByteArray(); } - *this << QByteArray::fromRawData(metaObject->className(), strlen(metaObject->className())); - if (_metadataType == NO_METADATA) { - return *this; - } - const PropertyWriterVector& propertyWriters = getPropertyWriters().value(metaObject); - *this << propertyWriters.size(); - QCryptographicHash hash(QCryptographicHash::Md5); - foreach (const PropertyWriter& propertyWriter, propertyWriters) { - _typeStreamerStreamer << propertyWriter.getStreamer(); - const QMetaProperty& property = propertyWriter.getProperty(); - if (_metadataType == FULL_METADATA) { - *this << QByteArray::fromRawData(property.name(), strlen(property.name())); - } else { - hash.addData(property.name(), strlen(property.name()) + 1); - } - } - if (_metadataType == HASH_METADATA) { - QByteArray hashResult = hash.result(); - write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE); + const char* name = streamer->getName(); + *this << QByteArray::fromRawData(name, strlen(name)); + if (_metadataType != NO_METADATA) { + streamer->writeMetadata(*this, _metadataType == FULL_METADATA); } return *this; } -Bitstream& Bitstream::operator>(ObjectReader& objectReader) { +Bitstream& Bitstream::operator>(ObjectStreamerPointer& streamer) { QByteArray className; *this >> className; if (className.isEmpty()) { - objectReader = ObjectReader(); + streamer = ObjectStreamerPointer(); return *this; } const QMetaObject* metaObject = _metaObjectSubstitutions.value(className); if (!metaObject) { metaObject = getMetaObjects().value(className); } - if (!metaObject) { - qWarning() << "Unknown class name: " << className << "\n"; + // start out with the streamer for the named class, if any + if (metaObject) { + streamer = getObjectStreamers().value(metaObject)->getSelf(); + } else { + streamer = ObjectStreamerPointer(); } if (_metadataType == NO_METADATA) { - objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject)); + if (!metaObject) { + qWarning() << "Unknown class name:" << className; + } return *this; } - int storedPropertyCount; - *this >> storedPropertyCount; - PropertyReaderVector properties(storedPropertyCount); - for (int i = 0; i < storedPropertyCount; i++) { + if (_genericsMode == ALL_GENERICS) { + streamer = readGenericObjectStreamer(className); + return *this; + } + if (!metaObject && _genericsMode == FALLBACK_GENERICS) { + streamer = readGenericObjectStreamer(className); + return *this; + } + int propertyCount; + *this >> propertyCount; + QVector properties(propertyCount); + for (int i = 0; i < propertyCount; i++) { TypeStreamerPointer typeStreamer; *this >> typeStreamer; QMetaProperty property = QMetaProperty(); @@ -1134,23 +1144,22 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { property = metaObject->property(metaObject->indexOfProperty(propertyName)); } } - properties[i] = PropertyReader(typeStreamer, property); + properties[i] = StreamerPropertyPair(typeStreamer, 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) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; if (metaObject) { - const PropertyWriterVector& propertyWriters = getPropertyWriters().value(metaObject); - if (propertyWriters.size() == properties.size()) { - for (int i = 0; i < propertyWriters.size(); i++) { - const PropertyWriter& propertyWriter = propertyWriters.at(i); - if (properties.at(i).getStreamer() != propertyWriter.getStreamer()) { + const QVector& localProperties = streamer->getProperties(); + if (localProperties.size() == properties.size()) { + for (int i = 0; i < localProperties.size(); i++) { + const StreamerPropertyPair& localProperty = localProperties.at(i); + if (localProperty.first != properties.at(i).first) { matches = false; break; } - const QMetaProperty& property = propertyWriter.getProperty(); - hash.addData(property.name(), strlen(property.name()) + 1); + hash.addData(localProperty.second.name(), strlen(localProperty.second.name()) + 1); } } else { matches = false; @@ -1160,11 +1169,24 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QByteArray remoteHashResult(localHashResult.size(), 0); read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); if (metaObject && matches && localHashResult == remoteHashResult) { - objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject)); return *this; } + } else if (metaObject) { + const QVector& localProperties = streamer->getProperties(); + if (localProperties.size() != properties.size()) { + streamer = ObjectStreamerPointer(new MappedObjectStreamer(metaObject, properties)); + return *this; + } + for (int i = 0; i < localProperties.size(); i++) { + const StreamerPropertyPair& property = properties.at(i); + if (localProperties.at(i).first != property.first || property.second.propertyIndex() != i) { + streamer = ObjectStreamerPointer(new MappedObjectStreamer(metaObject, properties)); + return *this; + } + } + return *this; } - objectReader = ObjectReader(className, metaObject, properties); + streamer = ObjectStreamerPointer(new MappedObjectStreamer(metaObject, properties)); return *this; } @@ -1405,12 +1427,12 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { QPointer reference = _sharedObjectReferences.value(originID); QPointer& pointer = _weakSharedObjectHash[id]; if (pointer) { - ObjectReader objectReader; - _metaObjectStreamer >> objectReader; + ObjectStreamerPointer objectStreamer; + _objectStreamerStreamer >> objectStreamer; if (reference) { - objectReader.readDelta(*this, reference.data(), pointer.data()); + objectStreamer->readRawDelta(*this, reference.data(), pointer.data()); } else { - objectReader.read(*this, pointer.data()); + objectStreamer->read(*this, pointer.data()); } } else { QObject* rawObject; @@ -1445,6 +1467,31 @@ void Bitstream::clearSharedObject(QObject* object) { const int MD5_HASH_SIZE = 16; +ObjectStreamerPointer Bitstream::readGenericObjectStreamer(const QByteArray& name) { + int propertyCount; + *this >> propertyCount; + QVector properties(propertyCount); + QByteArray hash; + if (propertyCount > 0) { + for (int i = 0; i < propertyCount; i++) { + TypeStreamerPointer streamer; + *this >> streamer; + QByteArray name; + if (_metadataType == FULL_METADATA) { + *this >> name; + } + properties[i] = StreamerNamePair(streamer, name); + } + if (_metadataType == HASH_METADATA) { + hash.resize(MD5_HASH_SIZE); + read(hash.data(), hash.size() * BITS_IN_BYTE); + } + } + ObjectStreamerPointer streamer = ObjectStreamerPointer(new GenericObjectStreamer(name, properties, hash)); + static_cast(streamer.data())->_weakSelf = streamer; + return streamer; +} + TypeStreamerPointer Bitstream::readGenericTypeStreamer(const QByteArray& name, int category) { TypeStreamerPointer streamer; switch (category) { @@ -1528,6 +1575,40 @@ QMultiHash& Bitstream::getMetaObjectSubC return metaObjectSubClasses; } +const QHash& Bitstream::getObjectStreamers() { + static QHash objectStreamers = createObjectStreamers(); + return objectStreamers; +} + +QHash Bitstream::createObjectStreamers() { + QHash objectStreamers; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + QVector properties; + for (int i = 0; i < metaObject->propertyCount(); i++) { + QMetaProperty property = metaObject->property(i); + if (!property.isStored()) { + continue; + } + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(ScopeNamePair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + properties.append(StreamerPropertyPair(streamer->getSelf(), property)); + } + } + ObjectStreamerPointer streamer = ObjectStreamerPointer(new MappedObjectStreamer(metaObject, properties)); + streamer->_self = streamer; + objectStreamers.insert(metaObject, streamer.data()); + } + return objectStreamers; +} + QHash& Bitstream::getTypeStreamers() { static QHash typeStreamers; return typeStreamers; @@ -1577,69 +1658,17 @@ const TypeStreamer* Bitstream::createInvalidTypeStreamer() { return streamer; } -const QHash& Bitstream::getPropertyReaders() { - static QHash propertyReaders = createPropertyReaders(); - return propertyReaders; +ObjectStreamer::ObjectStreamer(const QMetaObject* metaObject) : + _metaObject(metaObject) { } -QHash Bitstream::createPropertyReaders() { - QHash propertyReaders; - foreach (const QMetaObject* metaObject, getMetaObjects()) { - PropertyReaderVector& readers = propertyReaders[metaObject]; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; - } - const TypeStreamer* streamer; - if (property.isEnumType()) { - QMetaEnum metaEnum = property.enumerator(); - streamer = getEnumStreamers().value(ScopeNamePair( - QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), - QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); - } else { - streamer = getTypeStreamers().value(property.userType()); - } - if (streamer) { - readers.append(PropertyReader(streamer->getSelf(), property)); - } - } - } - return propertyReaders; +const QVector& ObjectStreamer::getProperties() const { + static QVector emptyProperties; + return emptyProperties; } -const QHash& Bitstream::getPropertyWriters() { - static QHash propertyWriters = createPropertyWriters(); - return propertyWriters; -} - -QHash Bitstream::createPropertyWriters() { - QHash propertyWriters; - foreach (const QMetaObject* metaObject, getMetaObjects()) { - PropertyWriterVector& writers = propertyWriters[metaObject]; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; - } - const TypeStreamer* streamer; - if (property.isEnumType()) { - QMetaEnum metaEnum = property.enumerator(); - streamer = getEnumStreamers().value(ScopeNamePair( - QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), - QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); - } else { - streamer = getTypeStreamers().value(property.userType()); - } - if (streamer) { - writers.append(PropertyWriter(property, streamer)); - } - } - } - return propertyWriters; -} - -MappedObjectStreamer::MappedObjectStreamer(const QVector& properties) : +MappedObjectStreamer::MappedObjectStreamer(const QMetaObject* metaObject, const QVector& properties) : + ObjectStreamer(metaObject), _properties(properties) { } @@ -1647,6 +1676,10 @@ const char* MappedObjectStreamer::getName() const { return _metaObject->className(); } +const QVector& MappedObjectStreamer::getProperties() const { + return _properties; +} + void MappedObjectStreamer::writeMetadata(Bitstream& out, bool full) const { out << _properties.size(); if (_properties.isEmpty()) { @@ -1667,13 +1700,13 @@ void MappedObjectStreamer::writeMetadata(Bitstream& out, bool full) const { } } -void MappedObjectStreamer::write(Bitstream& out, QObject* object) const { +void MappedObjectStreamer::write(Bitstream& out, const QObject* object) const { foreach (const StreamerPropertyPair& property, _properties) { property.first->write(out, property.second.read(object)); } } -void MappedObjectStreamer::writeDelta(Bitstream& out, QObject* object, QObject* reference) const { +void MappedObjectStreamer::writeRawDelta(Bitstream& out, const QObject* object, const QObject* reference) const { foreach (const StreamerPropertyPair& property, _properties) { property.first->writeDelta(out, property.second.read(object), (reference && reference->metaObject() == _metaObject) ? property.second.read(reference) : QVariant()); @@ -1693,14 +1726,14 @@ QObject* MappedObjectStreamer::read(Bitstream& in, QObject* object) const { return object; } -QObject* MappedObjectStreamer::readDelta(Bitstream& in, const QObject* reference, QObject* object) const { +QObject* MappedObjectStreamer::readRawDelta(Bitstream& in, const QObject* reference, QObject* object) const { if (!object && _metaObject) { object = _metaObject->newInstance(); } foreach (const StreamerPropertyPair& property, _properties) { QVariant value; - property.first->readDelta(in, value, (property.second.isValid() && reference) ? - property.second.read(reference) : QVariant()); + property.first->readDelta(in, value, (property.second.isValid() && reference && + reference->metaObject() == _metaObject) ? property.second.read(reference) : QVariant()); if (property.second.isValid() && object) { property.second.write(object, value); } @@ -1710,11 +1743,10 @@ QObject* MappedObjectStreamer::readDelta(Bitstream& in, const QObject* reference GenericObjectStreamer::GenericObjectStreamer(const QByteArray& name, const QVector& properties, const QByteArray& hash) : + ObjectStreamer(&GenericSharedObject::staticMetaObject), _name(name), _properties(properties), _hash(hash) { - - _metaObject = &GenericSharedObject::staticMetaObject; } const char* GenericObjectStreamer::getName() const { @@ -1744,17 +1776,22 @@ void GenericObjectStreamer::writeMetadata(Bitstream& out, bool full) const { } } -void GenericObjectStreamer::write(Bitstream& out, QObject* object) const { - const QVariantList& values = static_cast(object)->getValues(); +void GenericObjectStreamer::write(Bitstream& out, const QObject* object) const { + const QVariantList& values = static_cast(object)->getValues(); for (int i = 0; i < _properties.size(); i++) { _properties.at(i).first->write(out, values.at(i)); } } -void GenericObjectStreamer::writeDelta(Bitstream& out, QObject* object, QObject* reference) const { +void GenericObjectStreamer::writeRawDelta(Bitstream& out, const QObject* object, const QObject* reference) const { + const GenericSharedObject* genericObject = static_cast(object); + const GenericSharedObject* genericReference = (reference && + reference->metaObject() == &GenericSharedObject::staticMetaObject) ? + static_cast(reference) : NULL; for (int i = 0; i < _properties.size(); i++) { - _properties.at(i).first->writeDelta(out, static_cast(object)->getValues().at(i), reference ? - static_cast(reference)->getValues().at(i) : QVariant()); + _properties.at(i).first->writeDelta(out, genericObject->getValues().at(i), + (genericReference && genericReference->getStreamer() == genericObject->getStreamer()) ? + genericReference->getValues().at(i) : QVariant()); } } @@ -1770,7 +1807,7 @@ QObject* GenericObjectStreamer::read(Bitstream& in, QObject* object) const { return object; } -QObject* GenericObjectStreamer::readDelta(Bitstream& in, const QObject* reference, QObject* object) const { +QObject* GenericObjectStreamer::readRawDelta(Bitstream& in, const QObject* reference, QObject* object) const { if (!object) { object = new GenericSharedObject(_weakSelf); } @@ -1786,75 +1823,6 @@ QObject* GenericObjectStreamer::readDelta(Bitstream& in, const QObject* referenc return object; } -ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject, - const PropertyReaderVector& properties) : - _className(className), - _metaObject(metaObject), - _properties(properties) { -} - -QObject* ObjectReader::read(Bitstream& in, QObject* object) const { - if (!object && _metaObject) { - object = _metaObject->newInstance(); - } - foreach (const PropertyReader& property, _properties) { - property.read(in, object); - } - return object; -} - -QObject* ObjectReader::readDelta(Bitstream& in, const QObject* reference, QObject* object) const { - if (!object && _metaObject) { - object = _metaObject->newInstance(); - } - foreach (const PropertyReader& property, _properties) { - property.readDelta(in, object, reference); - } - return object; -} - -uint qHash(const ObjectReader& objectReader, uint seed) { - return qHash(objectReader.getClassName(), seed); -} - -QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader) { - return debug << objectReader.getClassName(); -} - -PropertyReader::PropertyReader(const TypeStreamerPointer& streamer, const QMetaProperty& property) : - _streamer(streamer), - _property(property) { -} - -void PropertyReader::read(Bitstream& in, QObject* object) const { - QVariant value = _streamer->read(in); - if (_property.isValid() && object) { - _property.write(object, value); - } -} - -void PropertyReader::readDelta(Bitstream& in, QObject* object, const QObject* reference) const { - QVariant value; - _streamer->readDelta(in, value, (_property.isValid() && reference) ? _property.read(reference) : QVariant()); - if (_property.isValid() && object) { - _property.write(object, value); - } -} - -PropertyWriter::PropertyWriter(const QMetaProperty& property, const TypeStreamer* streamer) : - _property(property), - _streamer(streamer) { -} - -void PropertyWriter::write(Bitstream& out, const QObject* object) const { - _streamer->write(out, _property.read(object)); -} - -void PropertyWriter::writeDelta(Bitstream& out, const QObject* object, const QObject* reference) const { - _streamer->writeDelta(out, _property.read(object), reference && object->metaObject() == reference->metaObject() ? - _property.read(reference) : QVariant()); -} - MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) : _name(name), _streamer(streamer) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 07e4b94568..10c28b9821 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -39,8 +39,6 @@ class GenericValue; class ObjectReader; class ObjectStreamer; class OwnedAttributeValue; -class PropertyReader; -class PropertyWriter; class TypeStreamer; typedef SharedObjectPointerTemplate AttributePointer; @@ -51,8 +49,6 @@ typedef QSharedPointer ObjectStreamerPointer; typedef QWeakPointer WeakObjectStreamerPointer; typedef QSharedPointer TypeStreamerPointer; typedef QWeakPointer WeakTypeStreamerPointer; -typedef QVector PropertyReaderVector; -typedef QVector PropertyWriterVector; typedef QPair QVariantPair; typedef QList QVariantPairList; @@ -207,7 +203,7 @@ public: class WriteMappings { public: - QHash metaObjectOffsets; + QHash objectStreamerOffsets; QHash typeStreamerOffsets; QHash attributeOffsets; QHash scriptStringOffsets; @@ -216,7 +212,7 @@ public: class ReadMappings { public: - QHash metaObjectValues; + QHash objectStreamerValues; QHash typeStreamerValues; QHash attributeValues; QHash scriptStringValues; @@ -403,7 +399,10 @@ public: Bitstream& operator<<(const QMetaObject* metaObject); Bitstream& operator>>(const QMetaObject*& metaObject); - Bitstream& operator>>(ObjectReader& objectReader); + + Bitstream& operator<<(const ObjectStreamer* streamer); + Bitstream& operator>>(const ObjectStreamer*& streamer); + Bitstream& operator>>(ObjectStreamerPointer& streamer); Bitstream& operator<<(const TypeStreamer* streamer); Bitstream& operator>>(const TypeStreamer*& streamer); @@ -421,11 +420,11 @@ public: Bitstream& operator<<(const SharedObjectPointer& object); Bitstream& operator>>(SharedObjectPointer& object); - Bitstream& operator<(const QMetaObject* metaObject); - Bitstream& operator>(ObjectReader& objectReader); + Bitstream& operator<(const ObjectStreamer* streamer); + Bitstream& operator>(ObjectStreamerPointer& streamer); Bitstream& operator<(const TypeStreamer* streamer); - Bitstream& operator>(TypeStreamerPointer& reader); + Bitstream& operator>(TypeStreamerPointer& streamer); Bitstream& operator<(const AttributePointer& attribute); Bitstream& operator>(AttributePointer& attribute); @@ -446,6 +445,7 @@ private slots: private: + ObjectStreamerPointer readGenericObjectStreamer(const QByteArray& name); TypeStreamerPointer readGenericTypeStreamer(const QByteArray& name, int category); QDataStream& _underlying; @@ -455,7 +455,7 @@ private: MetadataType _metadataType; GenericsMode _genericsMode; - RepeatedValueStreamer _metaObjectStreamer; + RepeatedValueStreamer _objectStreamerStreamer; RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; @@ -472,6 +472,9 @@ private: static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); + static const QHash& getObjectStreamers(); + static QHash createObjectStreamers(); + static const QHash& getEnumStreamers(); static QHash createEnumStreamers(); @@ -480,12 +483,6 @@ private: static const TypeStreamer* getInvalidTypeStreamer(); static const TypeStreamer* createInvalidTypeStreamer(); - - static const QHash& getPropertyReaders(); - static QHash createPropertyReaders(); - - static const QHash& getPropertyWriters(); - static QHash createPropertyWriters(); }; template inline void Bitstream::writeDelta(const T& value, const T& reference) { @@ -769,37 +766,46 @@ template inline Bitstream& Bitstream::operator>>(QHash& return *this; } +typedef QPair StreamerPropertyPair; + /// Contains the information required to stream an object. class ObjectStreamer { public: - virtual const char* getName() const = 0; + ObjectStreamer(const QMetaObject* metaObject); + + const QMetaObject* getMetaObject() const { return _metaObject; } + const ObjectStreamerPointer& getSelf() const { return _self; } + + virtual const char* getName() const = 0; + virtual const QVector& getProperties() const; virtual void writeMetadata(Bitstream& out, bool full) const = 0; - virtual void write(Bitstream& out, QObject* object) const = 0; - virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const = 0; + virtual void write(Bitstream& out, const QObject* object) const = 0; + virtual void writeRawDelta(Bitstream& out, const QObject* object, const QObject* reference) const = 0; virtual QObject* read(Bitstream& in, QObject* object = NULL) const = 0; - virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const = 0; + virtual QObject* readRawDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const = 0; protected: + + friend class Bitstream; const QMetaObject* _metaObject; ObjectStreamerPointer _self; }; -typedef QPair StreamerPropertyPair; - /// A streamer that maps to a local class. class MappedObjectStreamer : public ObjectStreamer { public: - MappedObjectStreamer(const QVector& properties); + MappedObjectStreamer(const QMetaObject* metaObject, const QVector& properties); virtual const char* getName() const; + virtual const QVector& getProperties() const; virtual void writeMetadata(Bitstream& out, bool full) const; - virtual void write(Bitstream& out, QObject* object) const; - virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const; + virtual void write(Bitstream& out, const QObject* object) const; + virtual void writeRawDelta(Bitstream& out, const QObject* object, const QObject* reference) const; virtual QObject* read(Bitstream& in, QObject* object = NULL) const; - virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; + virtual QObject* readRawDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; private: @@ -816,10 +822,10 @@ public: virtual const char* getName() const; virtual void writeMetadata(Bitstream& out, bool full) const; - virtual void write(Bitstream& out, QObject* object) const; - virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const; + virtual void write(Bitstream& out, const QObject* object) const; + virtual void writeRawDelta(Bitstream& out, const QObject* object, const QObject* reference) const; virtual QObject* read(Bitstream& in, QObject* object = NULL) const; - virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; + virtual QObject* readRawDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; private: @@ -831,69 +837,6 @@ private: QByteArray _hash; }; -/// Contains the information required to read an object from the stream. -class ObjectReader { -public: - - ObjectReader(const QByteArray& className = QByteArray(), const QMetaObject* metaObject = NULL, - const QVector& properties = QVector()); - - const QByteArray& getClassName() const { return _className; } - const QMetaObject* getMetaObject() const { return _metaObject; } - - QObject* read(Bitstream& in, QObject* object = NULL) const; - QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; - - bool operator==(const ObjectReader& other) const { return _className == other._className; } - bool operator!=(const ObjectReader& other) const { return _className != other._className; } - -private: - - QByteArray _className; - const QMetaObject* _metaObject; - QVector _properties; -}; - -uint qHash(const ObjectReader& objectReader, uint seed = 0); - -QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader); - -/// Contains the information required to read an object property from the stream and apply it. -class PropertyReader { -public: - - PropertyReader(const TypeStreamerPointer& streamer = TypeStreamerPointer(), - const QMetaProperty& property = QMetaProperty()); - - const TypeStreamerPointer& getStreamer() const { return _streamer; } - - void read(Bitstream& in, QObject* object) const; - void readDelta(Bitstream& in, QObject* object, const QObject* reference) const; - -private: - - TypeStreamerPointer _streamer; - QMetaProperty _property; -}; - -/// Contains the information required to obtain an object property and write it to the stream. -class PropertyWriter { -public: - - PropertyWriter(const QMetaProperty& property = QMetaProperty(), const TypeStreamer* streamer = NULL); - - const QMetaProperty& getProperty() const { return _property; } - const TypeStreamer* getStreamer() const { return _streamer; } - - void write(Bitstream& out, const QObject* object) const; - void writeDelta(Bitstream& out, const QObject* object, const QObject* reference) const; - -private: - - QMetaProperty _property; - const TypeStreamer* _streamer; -}; - /// Describes a metatype field. class MetaField { public: From 9fc84d6358abe2942cf8808faba84a56feda0588 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 13 Jun 2014 12:00:42 -0700 Subject: [PATCH 10/11] Generics up and running. --- libraries/metavoxels/src/Bitstream.cpp | 33 ++++++++++++++++++------- libraries/metavoxels/src/Bitstream.h | 6 ++++- libraries/metavoxels/src/SharedObject.h | 2 ++ tests/metavoxels/src/MetavoxelTests.cpp | 29 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 760b1fc646..80aa07b026 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -760,8 +760,7 @@ Bitstream& Bitstream::operator<<(const QVariant& value) { } const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); if (streamer) { - _typeStreamerStreamer << streamer->getStreamerToWrite(value); - streamer->write(*this, value); + streamer->writeVariant(*this, value); } else { qWarning() << "Non-streamable type: " << value.typeName() << "\n"; } @@ -774,7 +773,7 @@ Bitstream& Bitstream::operator>>(QVariant& value) { if (!streamer) { value = QVariant(); } else { - value = streamer->read(*this); + value = streamer->readVariant(*this); } return *this; } @@ -1889,6 +1888,15 @@ QVariant TypeStreamer::read(Bitstream& in) const { return QVariant(); } +void TypeStreamer::writeVariant(Bitstream& out, const QVariant& value) const { + out << this; + write(out, value); +} + +QVariant TypeStreamer::readVariant(Bitstream& in) const { + return read(in); +} + void TypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { if (value == reference) { out << false; @@ -2151,6 +2159,10 @@ const char* GenericTypeStreamer::getName() const { return _name.constData(); } +QVariant GenericTypeStreamer::readVariant(Bitstream& in) const { + return QVariant::fromValue(GenericValue(_weakSelf, read(in))); +} + GenericEnumTypeStreamer::GenericEnumTypeStreamer(const QByteArray& name, const QVector& values, int bits, const QByteArray& hash) : GenericTypeStreamer(name), @@ -2190,7 +2202,7 @@ void GenericEnumTypeStreamer::write(Bitstream& out, const QVariant& value) const QVariant GenericEnumTypeStreamer::read(Bitstream& in) const { int intValue = 0; in.read(&intValue, _bits); - return QVariant::fromValue(GenericValue(_weakSelf, intValue)); + return intValue; } TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const { @@ -2270,7 +2282,7 @@ QVariant GenericStreamableTypeStreamer::read(Bitstream& in) const { foreach (const StreamerNamePair& field, _fields) { values.append(field.first->read(in)); } - return QVariant::fromValue(GenericValue(_weakSelf, values)); + return values; } TypeStreamer::Category GenericStreamableTypeStreamer::getCategory() const { @@ -2337,7 +2349,7 @@ QVariant GenericListTypeStreamer::read(Bitstream& in) const { for (int i = 0; i < size; i++) { values.append(_valueStreamer->read(in)); } - return QVariant::fromValue(GenericValue(_weakSelf, values)); + return values; } TypeStreamer::Category GenericListTypeStreamer::getCategory() const { @@ -2443,13 +2455,16 @@ QVariant GenericMapTypeStreamer::read(Bitstream& in) const { QVariant value = _valueStreamer->read(in); values.append(QVariantPair(key, value)); } - return QVariant::fromValue(GenericValue(_weakSelf, QVariant::fromValue(values))); + return QVariant::fromValue(values); } TypeStreamer::Category GenericMapTypeStreamer::getCategory() const { return MAP_CATEGORY; } -const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const { - return value.value().getStreamer().data(); +void GenericValueStreamer::writeVariant(Bitstream& out, const QVariant& value) const { + GenericValue genericValue = value.value(); + out << genericValue.getStreamer().data(); + genericValue.getStreamer()->write(out, genericValue.getValue()); } + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 10c28b9821..1589473b0e 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -918,6 +918,9 @@ public: virtual void write(Bitstream& out, const QVariant& value) const; virtual QVariant read(Bitstream& in) const; + virtual void writeVariant(Bitstream& out, const QVariant& value) const; + virtual QVariant readVariant(Bitstream& in) const; + virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; @@ -1031,6 +1034,7 @@ public: GenericTypeStreamer(const QByteArray& name); virtual const char* getName() const; + virtual QVariant readVariant(Bitstream& in) const; protected: @@ -1260,7 +1264,7 @@ private: class GenericValueStreamer : public SimpleTypeStreamer { public: - virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const; + virtual void writeVariant(Bitstream& out, const QVariant& value) const; }; /// Macro for registering simple type streamers. diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 41c3c01ffe..15cd5eb0a1 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -41,6 +41,8 @@ public: /// Returns the unique local ID for this object. int getID() const { return _id; } + void setID(int id) { _weakHash.insert(_id = id, this); } + /// Returns the local origin ID for this object. int getOriginID() const { return _originID; } diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 6ec2331b14..6bd99a6c82 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -214,6 +214,35 @@ static bool testSerialization(Bitstream::MetadataType metadataType) { return true; } + // go back to the beginning and read everything as generics + inStream.device()->seek(0); + Bitstream genericIn(inStream, metadataType, Bitstream::ALL_GENERICS); + genericIn >> testObjectReadA; + genericIn >> testObjectReadB; + genericIn >> messageRead; + genericIn >> endRead; + + // reassign the ids + testObjectReadA->setID(testObjectWrittenA->getID()); + testObjectReadA->setOriginID(testObjectWrittenA->getOriginID()); + testObjectReadB->setID(testObjectWrittenB->getID()); + testObjectReadB->setOriginID(testObjectWrittenB->getOriginID()); + + // write it back out and compare + QByteArray compareArray; + QDataStream compareOutStream(&compareArray, QIODevice::WriteOnly); + Bitstream compareOut(compareOutStream, metadataType); + compareOut << testObjectReadA; + compareOut << testObjectReadB; + compareOut << messageRead; + compareOut << endRead; + compareOut.flush(); + + if (array != compareArray) { + qDebug() << "Mismatch between written/generic written streams."; + return true; + } + return false; } From 10875c5e61cfb056e0bbe1f260d8cd154e61b6fe Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 13 Jun 2014 12:12:17 -0700 Subject: [PATCH 11/11] Fix for setID. --- libraries/metavoxels/src/SharedObject.cpp | 5 +++++ libraries/metavoxels/src/SharedObject.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 47d69f4abe..05af5f1bf8 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -30,6 +30,11 @@ SharedObject::SharedObject() : _weakHash.insert(_id, this); } +void SharedObject::setID(int id) { + _weakHash.remove(_id); + _weakHash.insert(_id = id, this); +} + void SharedObject::incrementReferenceCount() { _referenceCount.ref(); } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 15cd5eb0a1..ba643b449c 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -41,7 +41,7 @@ public: /// Returns the unique local ID for this object. int getID() const { return _id; } - void setID(int id) { _weakHash.insert(_id = id, this); } + void setID(int id); /// Returns the local origin ID for this object. int getOriginID() const { return _originID; }