diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index d7e15a9dd6..80aa07b026 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -44,6 +44,11 @@ static int quatStreamer = Bitstream::registerTypeStreamer(qMetaTypeId static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); +static int genericValueStreamer = Bitstream::registerTypeStreamer( + qRegisterMetaType(), new GenericValueStreamer()); + +static int qVariantPairListMetaTypeId = qRegisterMetaType(); + IDStreamer::IDStreamer(Bitstream& stream) : _stream(stream), _bits(1) { @@ -92,7 +97,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,13 +117,14 @@ 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), - _metaObjectStreamer(*this), + _genericsMode(genericsMode), + _objectStreamerStreamer(*this), _typeStreamerStreamer(*this), _attributeStreamer(*this), _scriptStringStreamer(*this), @@ -189,7 +198,7 @@ void Bitstream::reset() { } Bitstream::WriteMappings Bitstream::getAndResetWriteMappings() { - WriteMappings mappings = { _metaObjectStreamer.getAndResetTransientOffsets(), + WriteMappings mappings = { _objectStreamerStreamer.getAndResetTransientOffsets(), _typeStreamerStreamer.getAndResetTransientOffsets(), _attributeStreamer.getAndResetTransientOffsets(), _scriptStringStreamer.getAndResetTransientOffsets(), @@ -198,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); @@ -226,7 +235,7 @@ void Bitstream::persistAndResetWriteMappings() { } Bitstream::ReadMappings Bitstream::getAndResetReadMappings() { - ReadMappings mappings = { _metaObjectStreamer.getAndResetTransientValues(), + ReadMappings mappings = { _objectStreamerStreamer.getAndResetTransientValues(), _typeStreamerStreamer.getAndResetTransientValues(), _attributeStreamer.getAndResetTransientValues(), _scriptStringStreamer.getAndResetTransientValues(), @@ -235,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); @@ -294,27 +303,27 @@ 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) { 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) { @@ -751,8 +760,7 @@ Bitstream& Bitstream::operator<<(const QVariant& value) { } const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); if (streamer) { - _typeStreamerStreamer << streamer; - streamer->write(*this, value); + streamer->writeVariant(*this, value); } else { qWarning() << "Non-streamable type: " << value.typeName() << "\n"; } @@ -760,12 +768,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->readVariant(*this); } return *this; } @@ -793,40 +801,62 @@ 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; + _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; } @@ -836,14 +866,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; } @@ -1056,57 +1086,55 @@ 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++) { - TypeReader typeReader; - *this >> typeReader; + 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(); if (_metadataType == FULL_METADATA) { QByteArray propertyName; @@ -1115,23 +1143,22 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { property = metaObject->property(metaObject->indexOfProperty(propertyName)); } } - properties[i] = PropertyReader(typeReader, 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).getReader().matchesExactly(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; @@ -1141,11 +1168,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; } @@ -1156,102 +1196,64 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { } const char* typeName = streamer->getName(); *this << QByteArray::fromRawData(typeName, strlen(typeName)); - if (_metadataType == NO_METADATA) { - return *this; - } - TypeReader::Type type = streamer->getReaderType(); - *this << (int)type; - switch (type) { - case TypeReader::SIMPLE_TYPE: - return *this; - - case TypeReader::ENUM_TYPE: { - 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 TypeReader::LIST_TYPE: - case TypeReader::SET_TYPE: - return *this << streamer->getValueStreamer(); - - case TypeReader::MAP_TYPE: - 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; } -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); } } - if (!streamer) { - qWarning() << "Unknown type name: " << typeName << "\n"; + // start out with the base, if any + if (baseStreamer) { + streamer = baseStreamer->getSelf(); + } else { + streamer = TypeStreamerPointer(); } if (_metadataType == NO_METADATA) { - reader = TypeReader(typeName, streamer); + if (!baseStreamer) { + qWarning() << "Unknown type name:" << typeName; + } return *this; } - int type; - *this >> type; - switch (type) { - case TypeReader::SIMPLE_TYPE: - reader = TypeReader(typeName, streamer); + int category; + *this >> category; + if (category == TypeStreamer::SIMPLE_CATEGORY) { + if (!streamer) { + qWarning() << "Unknown type name:" << typeName; + } + return *this; + } + if (_genericsMode == ALL_GENERICS) { + streamer = readGenericTypeStreamer(typeName, category); + return *this; + } + if (!baseStreamer) { + if (_genericsMode == FALLBACK_GENERICS) { + streamer = readGenericTypeStreamer(typeName, category); return *this; - - case TypeReader::ENUM_TYPE: { + } + baseStreamer = getInvalidTypeStreamer(); + } + 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->getMetaEnum(); QHash mappings; bool matches = (keyCount == metaEnum.keyCount()); int highestValue = 0; @@ -1266,17 +1268,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->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); @@ -1286,37 +1287,29 @@ 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->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->getCategory() == TypeStreamer::MAP_CATEGORY && + keyStreamer == baseStreamer->getKeyStreamer() && valueStreamer == baseStreamer->getValueStreamer())) { + streamer = TypeStreamerPointer(new MappedMapTypeStreamer(baseStreamer, keyStreamer, valueStreamer)); } return *this; } @@ -1324,70 +1317,60 @@ 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); - } + 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 (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())) { - 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 (streamer && matches && localHashResult == remoteHashResult) { + if (matches && localHashResult == remoteHashResult) { // since everything is the same, we can use the default streamer - reader = TypeReader(typeName, streamer); return *this; } - } else if (streamer) { - // if all fields are the same type and in the right order, we can use the (more efficient) default streamer - const QVector& localFields = streamer->getMetaFields(); - if (fieldCount != localFields.size()) { - reader = TypeReader(typeName, streamer, 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); - return *this; - } - } - reader = TypeReader(typeName, streamer); + } + // 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; } - reader = TypeReader(typeName, streamer, fields); + 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; } @@ -1443,12 +1426,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; @@ -1481,6 +1464,106 @@ 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) { + 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; @@ -1491,6 +1574,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; @@ -1528,374 +1645,181 @@ QHash Bitstream::createEnumStreamersByName() { return enumStreamersByName; } -const QHash& Bitstream::getPropertyReaders() { - static QHash propertyReaders = createPropertyReaders(); - return propertyReaders; +const TypeStreamer* Bitstream::getInvalidTypeStreamer() { + const TypeStreamer* streamer = createInvalidTypeStreamer(); + return streamer; } -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(TypeReader(QByteArray(), streamer), property)); - } - } - } - return propertyReaders; +const TypeStreamer* Bitstream::createInvalidTypeStreamer() { + TypeStreamer* streamer = new TypeStreamer(); + streamer->_type = QMetaType::UnknownType; + streamer->_self = TypeStreamerPointer(streamer); + return streamer; } -const QHash& Bitstream::getPropertyWriters() { - static QHash propertyWriters = createPropertyWriters(); - return propertyWriters; +ObjectStreamer::ObjectStreamer(const QMetaObject* metaObject) : + _metaObject(metaObject) { } -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; +const QVector& ObjectStreamer::getProperties() const { + static QVector emptyProperties; + return emptyProperties; } -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), - _metaObject(metaObject), +MappedObjectStreamer::MappedObjectStreamer(const QMetaObject* metaObject, const QVector& properties) : + ObjectStreamer(metaObject), _properties(properties) { } -QObject* ObjectReader::read(Bitstream& in, QObject* object) const { +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()) { + 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, const QObject* object) const { + foreach (const StreamerPropertyPair& property, _properties) { + property.first->write(out, property.second.read(object)); + } +} + +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()); + } +} + +QObject* MappedObjectStreamer::read(Bitstream& in, QObject* object) const { if (!object && _metaObject) { object = _metaObject->newInstance(); } - foreach (const PropertyReader& property, _properties) { - property.read(in, object); + foreach (const StreamerPropertyPair& property, _properties) { + QVariant value = property.first->read(in); + if (property.second.isValid() && object) { + property.second.write(object, value); + } } return object; } -QObject* ObjectReader::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 PropertyReader& property, _properties) { - property.readDelta(in, object, reference); + foreach (const StreamerPropertyPair& property, _properties) { + QVariant value; + 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); + } } return object; } -uint qHash(const ObjectReader& objectReader, uint seed) { - return qHash(objectReader.getClassName(), seed); +GenericObjectStreamer::GenericObjectStreamer(const QByteArray& name, const QVector& properties, + const QByteArray& hash) : + ObjectStreamer(&GenericSharedObject::staticMetaObject), + _name(name), + _properties(properties), + _hash(hash) { } -QDebug& operator<<(QDebug& debug, const ObjectReader& objectReader) { - return debug << objectReader.getClassName(); +const char* GenericObjectStreamer::getName() const { + return _name.constData(); } -PropertyReader::PropertyReader(const TypeReader& reader, const QMetaProperty& property) : - _reader(reader), - _property(property) { -} - -void PropertyReader::read(Bitstream& in, QObject* object) const { - QVariant value = _reader.read(in); - if (_property.isValid() && object) { - _property.write(object, value); +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 PropertyReader::readDelta(Bitstream& in, QObject* object, const QObject* reference) const { - QVariant value; - _reader.readDelta(in, value, (_property.isValid() && reference) ? _property.read(reference) : QVariant()); - if (_property.isValid() && object) { - _property.write(object, value); +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)); } } -PropertyWriter::PropertyWriter(const QMetaProperty& property, const TypeStreamer* streamer) : - _property(property), - _streamer(streamer) { +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, genericObject->getValues().at(i), + (genericReference && genericReference->getStreamer() == genericObject->getStreamer()) ? + genericReference->getValues().at(i) : QVariant()); + } } -void PropertyWriter::write(Bitstream& out, const QObject* object) const { - _streamer->write(out, _property.read(object)); +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; } -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()); +QObject* GenericObjectStreamer::readRawDelta(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; } MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) : @@ -1903,6 +1827,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() { } @@ -1910,6 +1847,83 @@ const char* TypeStreamer::getName() const { return QMetaType::typeName(_type); } +const TypeStreamer* TypeStreamer::getStreamerToWrite(const QVariant& value) const { + 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; +} + +void TypeStreamer::write(Bitstream& out, const QVariant& value) const { + // nothing by default +} + +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; + } else { + out << true; + writeRawDelta(out, value, reference); + } +} + +void TypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + 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 { + // 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 } @@ -1931,8 +1945,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 { @@ -1993,23 +2007,46 @@ 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 { return _name.constData(); } -TypeReader::Type EnumTypeStreamer::getReaderType() const { - return TypeReader::ENUM_TYPE; +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; } int EnumTypeStreamer::getBits() const { @@ -2094,3 +2131,340 @@ void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) : + _baseStreamer(baseStreamer), + _bits(bits), + _mappings(mappings) { +} + +QVariant MappedEnumTypeStreamer::read(Bitstream& in) const { + QVariant object = QVariant(_baseStreamer->getType(), 0); + int value = 0; + in.read(&value, _bits); + _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); + _baseStreamer->setEnumValue(object, value, _mappings); +} + +GenericTypeStreamer::GenericTypeStreamer(const QByteArray& name) : + _name(name) { +} + +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), + _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); +} + +QVariant GenericEnumTypeStreamer::read(Bitstream& in) const { + int intValue = 0; + in.read(&intValue, _bits); + return intValue; +} + +TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const { + return ENUM_CATEGORY; +} + +MappedStreamableTypeStreamer::MappedStreamableTypeStreamer(const TypeStreamer* baseStreamer, + const QVector& fields) : + _baseStreamer(baseStreamer), + _fields(fields) { +} + +QVariant MappedStreamableTypeStreamer::read(Bitstream& in) const { + QVariant object = QVariant(_baseStreamer->getType(), 0); + foreach (const StreamerIndexPair& pair, _fields) { + QVariant value = pair.first->read(in); + if (pair.second != -1) { + _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) { + pair.first->readDelta(in, value, _baseStreamer->getField(reference, pair.second)); + _baseStreamer->setField(object, pair.second, value); + } else { + pair.first->readDelta(in, value, QVariant()); + } + } +} + +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(); + if (_fields.isEmpty()) { + return; + } + 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)); + } +} + +QVariant GenericStreamableTypeStreamer::read(Bitstream& in) const { + QVariantList values; + foreach (const StreamerNamePair& field, _fields) { + values.append(field.first->read(in)); + } + return values; +} + +TypeStreamer::Category GenericStreamableTypeStreamer::getCategory() const { + return STREAMABLE_CATEGORY; +} + +MappedListTypeStreamer::MappedListTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) : + _baseStreamer(baseStreamer), + _valueStreamer(valueStreamer) { +} + +QVariant MappedListTypeStreamer::read(Bitstream& in) const { + QVariant object = QVariant(_baseStreamer->getType(), 0); + int size; + in >> size; + for (int i = 0; i < size; i++) { + QVariant value = _valueStreamer->read(in); + _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 (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)); + } + } +} + +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); + } +} + +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 values; +} + +TypeStreamer::Category GenericListTypeStreamer::getCategory() const { + return LIST_CATEGORY; +} + +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->remove(object, value)) { + _baseStreamer->insert(object, value); + } + } +} + +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), + _keyStreamer(keyStreamer), + _valueStreamer(valueStreamer) { +} + +QVariant MappedMapTypeStreamer::read(Bitstream& in) const { + 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); + _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); + _baseStreamer->insert(object, key, value); + } + int modified; + in >> modified; + for (int i = 0; i < modified; i++) { + QVariant key = _keyStreamer->read(in); + QVariant value; + _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); + _baseStreamer->remove(object, key); + } +} + +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); + } +} + +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(values); +} + +TypeStreamer::Category GenericMapTypeStreamer::getCategory() const { + return MAP_CATEGORY; +} + +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 d05f6574c0..1589473b0e 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -35,19 +35,25 @@ class QUrl; class Attribute; class AttributeValue; class Bitstream; -class FieldReader; +class GenericValue; class ObjectReader; +class ObjectStreamer; class OwnedAttributeValue; -class PropertyReader; -class PropertyWriter; -class TypeReader; class TypeStreamer; typedef SharedObjectPointerTemplate AttributePointer; typedef QPair ScopeNamePair; -typedef QVector PropertyReaderVector; -typedef QVector PropertyWriterVector; +typedef QPair NameIntPair; +typedef QSharedPointer ObjectStreamerPointer; +typedef QWeakPointer WeakObjectStreamerPointer; +typedef QSharedPointer TypeStreamerPointer; +typedef QWeakPointer WeakTypeStreamerPointer; + +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 @@ -197,7 +203,7 @@ public: class WriteMappings { public: - QHash metaObjectOffsets; + QHash objectStreamerOffsets; QHash typeStreamerOffsets; QHash attributeOffsets; QHash scriptStringOffsets; @@ -206,8 +212,8 @@ public: class ReadMappings { public: - QHash metaObjectValues; - QHash typeStreamerValues; + QHash objectStreamerValues; + QHash typeStreamerValues; QHash attributeValues; QHash scriptStringValues; QHash sharedObjectValues; @@ -232,8 +238,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 +379,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); @@ -381,11 +399,14 @@ 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); - Bitstream& operator>>(TypeReader& reader); + Bitstream& operator>>(TypeStreamerPointer& streamer); Bitstream& operator<<(const AttributePointer& attribute); Bitstream& operator>>(AttributePointer& attribute); @@ -399,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>(TypeReader& reader); + Bitstream& operator>(TypeStreamerPointer& streamer); Bitstream& operator<(const AttributePointer& attribute); Bitstream& operator>(AttributePointer& attribute); @@ -424,14 +445,18 @@ private slots: private: + ObjectStreamerPointer readGenericObjectStreamer(const QByteArray& name); + TypeStreamerPointer readGenericTypeStreamer(const QByteArray& name, int category); + QDataStream& _underlying; quint8 _byte; int _position; MetadataType _metadataType; + GenericsMode _genericsMode; - RepeatedValueStreamer _metaObjectStreamer; - RepeatedValueStreamer _typeStreamerStreamer; + RepeatedValueStreamer _objectStreamerStreamer; + RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; RepeatedValueStreamer _sharedObjectStreamer; @@ -447,17 +472,17 @@ private: static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); + static const QHash& getObjectStreamers(); + static QHash createObjectStreamers(); + static const QHash& getEnumStreamers(); static QHash createEnumStreamers(); static const QHash& getEnumStreamersByName(); static QHash createEnumStreamersByName(); - static const QHash& getPropertyReaders(); - static QHash createPropertyReaders(); - - static const QHash& getPropertyWriters(); - static QHash createPropertyWriters(); + static const TypeStreamer* getInvalidTypeStreamer(); + static const TypeStreamer* createInvalidTypeStreamer(); }; template inline void Bitstream::writeDelta(const T& value, const T& reference) { @@ -741,133 +766,75 @@ template inline Bitstream& Bitstream::operator>>(QHash& return *this; } -typedef QSharedPointer TypeReaderPointer; +typedef QPair StreamerPropertyPair; -/// Contains the information required to read a type from the stream. -class TypeReader { +/// Contains the information required to stream an object. +class ObjectStreamer { 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); + ObjectStreamer(const QMetaObject* metaObject); - 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: - - 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; } + 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, 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* readRawDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const = 0; + +protected: + + friend class Bitstream; - 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; + ObjectStreamerPointer _self; }; -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 { +/// A streamer that maps to a local class. +class MappedObjectStreamer : public ObjectStreamer { public: - PropertyReader(const TypeReader& reader = TypeReader(), const QMetaProperty& property = QMetaProperty()); - - const TypeReader& getReader() const { return _reader; } - - void read(Bitstream& in, QObject* object) const; - void readDelta(Bitstream& in, QObject* object, const QObject* reference) const; - -private: - - TypeReader _reader; - 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; + 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, 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* readRawDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; + private: - QMetaProperty _property; - const TypeStreamer* _streamer; + 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, 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* readRawDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const; + +private: + + friend class Bitstream; + + QByteArray _name; + WeakObjectStreamerPointer _weakSelf; + QVector _properties; + QByteArray _hash; }; /// Describes a metatype field. @@ -890,27 +857,75 @@ 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: + enum Category { SIMPLE_CATEGORY, ENUM_CATEGORY, STREAMABLE_CATEGORY, LIST_CATEGORY, SET_CATEGORY, MAP_CATEGORY }; + 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 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; + 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 writeVariant(Bitstream& out, const QVariant& value) const; + virtual QVariant readVariant(Bitstream& in) 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 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; + virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; virtual void setEnumValue(QVariant& object, int value, const QHash& mappings) const; @@ -919,7 +934,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; @@ -937,9 +952,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); @@ -971,7 +989,8 @@ public: EnumTypeStreamer(const QMetaEnum& metaEnum); virtual const char* getName() const; - virtual TypeReader::Type getReaderType() const; + virtual void writeMetadata(Bitstream& out, bool full) const; + virtual Category getCategory() const; virtual int getBits() const; virtual QMetaEnum getMetaEnum() const; virtual bool equal(const QVariant& first, const QVariant& second) const; @@ -992,11 +1011,62 @@ 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; +}; + +/// 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; + virtual QVariant readVariant(Bitstream& in) const; + +protected: + + friend class Bitstream; + + QByteArray _name; + WeakTypeStreamerPointer _weakSelf; +}; + +/// 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 QVariant read(Bitstream& in) const; + virtual Category getCategory() const; + +private: + + QVector _values; + int _bits; + QByteArray _hash; +}; + /// A streamer for types compiled by mtc. 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 { @@ -1005,6 +1075,40 @@ 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; +}; + +/// 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 QVariant read(Bitstream& in) const; + virtual Category getCategory() const; + +private: + + QVector _fields; + QByteArray _hash; +}; + /// Base template for collection streamers. template class CollectionTypeStreamer : public SimpleTypeStreamer { }; @@ -1013,7 +1117,8 @@ template class CollectionTypeStreamer : public SimpleTypeStreamer { template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; } + 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 { static_cast*>(object.data())->append(value.value()); } @@ -1029,7 +1134,8 @@ public: template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; } + 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 { static_cast*>(object.data())->append(value.value()); } @@ -1041,11 +1147,43 @@ 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 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 QVariant read(Bitstream& in) const; + virtual Category getCategory() const; + +private: + + TypeStreamerPointer _valueStreamer; +}; + /// A streamer for set types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: - virtual TypeReader::Type getReaderType() const { return TypeReader::SET_TYPE; } + 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 { static_cast*>(object.data())->insert(value.value()); } @@ -1053,11 +1191,30 @@ 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 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 TypeReader::Type getReaderType() const { return TypeReader::MAP_TYPE; } + 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()); } virtual void insert(QVariant& object, const QVariant& key, const QVariant& value) const { @@ -1068,6 +1225,48 @@ 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; +}; + +/// 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 QVariant read(Bitstream& in) const; + virtual Category getCategory() const; + +private: + + TypeStreamerPointer _keyStreamer; + TypeStreamerPointer _valueStreamer; +}; + +/// A streamer class for generic values. +class GenericValueStreamer : public SimpleTypeStreamer { +public: + + virtual void writeVariant(Bitstream& out, 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()); 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(); } } 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 41c3c01ffe..ba643b449c 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); + /// 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; }