From 6db385de7a738e746dc53faab7da4dd1128dfb75 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 2 Jun 2014 15:16:08 -0700 Subject: [PATCH] Ported over fixes that I made when working on delta-encoding for avatars. --- libraries/metavoxels/src/Bitstream.cpp | 58 ++++++++++-- libraries/metavoxels/src/Bitstream.h | 92 +++++++++++++++++++- libraries/metavoxels/src/DatagramSequencer.h | 2 +- libraries/metavoxels/src/SharedObject.cpp | 41 +++++---- libraries/metavoxels/src/SharedObject.h | 23 +++-- 5 files changed, 184 insertions(+), 32 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index ad929e533c..b3d5817fe9 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -193,7 +193,7 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { continue; } connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); - QPointer& reference = _sharedObjectReferences[it.key()->getID()]; + QPointer& reference = _sharedObjectReferences[it.key()->getOriginID()]; if (reference) { _sharedObjectStreamer.removePersistentID(reference); reference->disconnect(this); @@ -227,7 +227,7 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { if (!it.value()) { continue; } - QPointer& reference = _sharedObjectReferences[it.value()->getRemoteID()]; + QPointer& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()]; if (reference) { _sharedObjectStreamer.removePersistentValue(reference.data()); } @@ -411,6 +411,10 @@ Bitstream& Bitstream::operator>>(QUrl& url) { } Bitstream& Bitstream::operator<<(const QVariant& value) { + if (!value.isValid()) { + _typeStreamerStreamer << NULL; + return *this; + } const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); if (streamer) { _typeStreamerStreamer << streamer; @@ -424,7 +428,11 @@ Bitstream& Bitstream::operator<<(const QVariant& value) { Bitstream& Bitstream::operator>>(QVariant& value) { TypeReader reader; _typeStreamerStreamer >> reader; - value = reader.read(*this); + if (reader.getTypeName().isEmpty()) { + value = QVariant(); + } else { + value = reader.read(*this); + } return *this; } @@ -656,6 +664,10 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { } Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { + if (!streamer) { + *this << QByteArray(); + return *this; + } const char* typeName = QMetaType::typeName(streamer->getType()); *this << QByteArray::fromRawData(typeName, strlen(typeName)); if (_metadataType == NO_METADATA) { @@ -702,6 +714,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { Bitstream& Bitstream::operator>(TypeReader& reader) { QByteArray typeName; *this >> typeName; + if (typeName.isEmpty()) { + reader = TypeReader(); + return *this; + } const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); if (!streamer) { streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); @@ -847,9 +863,10 @@ Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { return *this << (int)0; } *this << object->getID(); - QPointer reference = _sharedObjectReferences.value(object->getID()); + *this << object->getOriginID(); + QPointer reference = _sharedObjectReferences.value(object->getOriginID()); if (reference) { - writeRawDelta((QObject*)object.data(), (QObject*)reference.data()); + writeRawDelta((const QObject*)object.data(), (const QObject*)reference.data()); } else { *this << (QObject*)object.data(); } @@ -863,7 +880,9 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { object = SharedObjectPointer(); return *this; } - QPointer reference = _sharedObjectReferences.value(id); + int originID; + *this >> originID; + QPointer reference = _sharedObjectReferences.value(originID); QPointer& pointer = _weakSharedObjectHash[id]; if (pointer) { ObjectReader objectReader; @@ -876,15 +895,19 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { } else { QObject* rawObject; if (reference) { - readRawDelta(rawObject, (QObject*)reference.data()); + readRawDelta(rawObject, (const QObject*)reference.data()); } else { *this >> rawObject; } pointer = static_cast(rawObject); if (pointer) { + if (reference) { + pointer->setOriginID(reference->getOriginID()); + } pointer->setRemoteID(id); + pointer->setRemoteOriginID(originID); } else { - qDebug() << "Null object" << pointer << reference; + qDebug() << "Null object" << pointer << reference << id; } } object = static_cast(pointer.data()); @@ -893,7 +916,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { void Bitstream::clearSharedObject(QObject* object) { SharedObject* sharedObject = static_cast(object); - _sharedObjectReferences.remove(sharedObject->getID()); + _sharedObjectReferences.remove(sharedObject->getOriginID()); int id = _sharedObjectStreamer.takePersistentID(sharedObject); if (id != 0) { emit sharedObjectCleared(id); @@ -1099,6 +1122,10 @@ 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) { @@ -1152,6 +1179,10 @@ 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 TypeReader& reader, const QMetaProperty& property) : _reader(reader), _property(property) { @@ -1236,3 +1267,12 @@ QVariant TypeStreamer::getValue(const QVariant& object, int index) const { void TypeStreamer::setValue(QVariant& object, int index, const QVariant& value) const { // nothing by default } + +QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer) { + return debug << (typeStreamer ? QMetaType::typeName(typeStreamer->getType()) : "null"); +} + +QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { + return debug << (metaObject ? metaObject->className() : "null"); +} + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 34b66eb9f2..544d6dbd78 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -294,6 +294,9 @@ public: template void writeRawDelta(const QList& value, const QList& reference); template void readRawDelta(QList& value, const QList& reference); + template void writeRawDelta(const QVector& value, const QVector& reference); + template void readRawDelta(QVector& value, const QVector& reference); + template void writeRawDelta(const QSet& value, const QSet& reference); template void readRawDelta(QSet& value, const QSet& reference); @@ -339,6 +342,9 @@ public: template Bitstream& operator<<(const QList& list); template Bitstream& operator>>(QList& list); + template Bitstream& operator<<(const QVector& list); + template Bitstream& operator>>(QVector& list); + template Bitstream& operator<<(const QSet& set); template Bitstream& operator>>(QSet& set); @@ -472,6 +478,36 @@ template inline void Bitstream::readRawDelta(QList& value, const QLi } } +template inline void Bitstream::writeRawDelta(const QVector& value, const QVector& reference) { + *this << value.size(); + *this << reference.size(); + for (int i = 0; i < value.size(); i++) { + if (i < reference.size()) { + writeDelta(value.at(i), reference.at(i)); + } else { + *this << value.at(i); + } + } +} + +template inline void Bitstream::readRawDelta(QVector& value, const QVector& reference) { + value = reference; + int size, referenceSize; + *this >> size >> referenceSize; + if (size < value.size()) { + value.erase(value.begin() + size, value.end()); + } + for (int i = 0; i < size; i++) { + if (i < referenceSize) { + readDelta(value[i], reference.at(i)); + } else { + T element; + *this >> element; + value.append(element); + } + } +} + template inline void Bitstream::writeRawDelta(const QSet& value, const QSet& reference) { int addedOrRemoved = 0; foreach (const T& element, value) { @@ -600,6 +636,27 @@ template inline Bitstream& Bitstream::operator>>(QList& list) { return *this; } +template inline Bitstream& Bitstream::operator<<(const QVector& vector) { + *this << vector.size(); + foreach (const T& entry, vector) { + *this << entry; + } + return *this; +} + +template inline Bitstream& Bitstream::operator>>(QVector& vector) { + int size; + *this >> size; + vector.clear(); + vector.reserve(size); + for (int i = 0; i < size; i++) { + T entry; + *this >> entry; + vector.append(entry); + } + return *this; +} + template inline Bitstream& Bitstream::operator<<(const QSet& set) { *this << set.size(); foreach (const T& entry, set) { @@ -683,6 +740,8 @@ private: 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: @@ -726,6 +785,8 @@ private: 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: @@ -808,6 +869,10 @@ private: int _type; }; +QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer); + +QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject); + /// A streamer that works with Bitstream's operators. template class SimpleTypeStreamer : public TypeStreamer { public: @@ -818,11 +883,11 @@ public: virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { out.writeDelta(value.value(), reference.value()); } virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { - in.readDelta(*static_cast(value.data()), reference.value()); } + T rawValue; in.readDelta(rawValue, reference.value()); value = QVariant::fromValue(rawValue); } virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { out.writeRawDelta(value.value(), reference.value()); } virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { - in.readRawDelta(*static_cast(value.data()), reference.value()); } + T rawValue; in.readRawDelta(rawValue, reference.value()); value = QVariant::fromValue(rawValue); } }; /// A streamer for types compiled by mtc. @@ -858,6 +923,22 @@ public: static_cast*>(object.data())->replace(index, value.value()); } }; +/// A streamer for vector types. +template class CollectionTypeStreamer > : public SimpleTypeStreamer > { +public: + + virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; } + 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()); } + virtual void prune(QVariant& object, int size) const { + QVector* list = static_cast*>(object.data()); list->erase(list->begin() + size, list->end()); } + virtual QVariant getValue(const QVariant& object, int index) const { + return QVariant::fromValue(static_cast*>(object.constData())->at(index)); } + virtual void setValue(QVariant& object, int index, const QVariant& value) const { + static_cast*>(object.data())->replace(index, value.value()); } +}; + /// A streamer for set types. template class CollectionTypeStreamer > : public SimpleTypeStreamer > { public: @@ -940,6 +1021,13 @@ template int registerStreamableMetaType() { return type; } +/// Registers a collection type and its streamer. +template int registerCollectionMetaType() { + int type = qRegisterMetaType(); + Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer()); + return type; +} + /// Flags a class as streamable (use as you would Q_OBJECT). #define STREAMABLE public: \ static const int Type; \ diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index ce9f36ba33..cf6ded74da 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -19,7 +19,7 @@ #include #include -#include "Bitstream.h" +#include "AttributeRegistry.h" class ReliableChannel; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index b578d70959..47d69f4abe 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -23,7 +23,9 @@ REGISTER_META_OBJECT(SharedObject) SharedObject::SharedObject() : _id(++_lastID), - _remoteID(0) { + _originID(_id), + _remoteID(0), + _remoteOriginID(0) { _weakHash.insert(_id, this); } @@ -39,26 +41,33 @@ void SharedObject::decrementReferenceCount() { } } -SharedObject* SharedObject::clone(bool withID) const { +SharedObject* SharedObject::clone(bool withID, SharedObject* target) const { // default behavior is to make a copy using the no-arg constructor and copy the stored properties const QMetaObject* metaObject = this->metaObject(); - SharedObject* newObject = static_cast(metaObject->newInstance()); + if (!target) { + target = static_cast(metaObject->newInstance()); + } for (int i = 0; i < metaObject->propertyCount(); i++) { QMetaProperty property = metaObject->property(i); if (property.isStored()) { - property.write(newObject, property.read(this)); + if (property.userType() == qMetaTypeId()) { + SharedObject* value = property.read(this).value().data(); + property.write(target, QVariant::fromValue(value ? value->clone(withID) : value)); + } else { + property.write(target, property.read(this)); + } } } foreach (const QByteArray& propertyName, dynamicPropertyNames()) { - newObject->setProperty(propertyName, property(propertyName)); + target->setProperty(propertyName, property(propertyName)); } if (withID) { - newObject->setID(_id); + target->setOriginID(_originID); } - return newObject; + return target; } -bool SharedObject::equals(const SharedObject* other) const { +bool SharedObject::equals(const SharedObject* other, bool sharedAncestry) const { if (!other) { return false; } @@ -67,7 +76,7 @@ bool SharedObject::equals(const SharedObject* other) const { } // default behavior is to compare the properties const QMetaObject* metaObject = this->metaObject(); - if (metaObject != other->metaObject()) { + if (metaObject != other->metaObject() && !sharedAncestry) { return false; } for (int i = 0; i < metaObject->propertyCount(); i++) { @@ -92,13 +101,15 @@ void SharedObject::dump(QDebug debug) const { debug << this; const QMetaObject* metaObject = this->metaObject(); for (int i = 0; i < metaObject->propertyCount(); i++) { - debug << metaObject->property(i).name() << metaObject->property(i).read(this); + QMetaProperty property = metaObject->property(i); + if (property.isStored()) { + debug << property.name() << property.read(this); + } + } + QList dynamicPropertyNames = this->dynamicPropertyNames(); + foreach (const QByteArray& propertyName, dynamicPropertyNames) { + debug << propertyName << property(propertyName); } -} - -void SharedObject::setID(int id) { - _weakHash.remove(_id); - _weakHash.insert(_id = id, this); } int SharedObject::_lastID = 0; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index aba6b86bea..41c3c01ffe 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -41,31 +41,44 @@ public: /// Returns the unique local ID for this object. int getID() const { return _id; } + /// Returns the local origin ID for this object. + int getOriginID() const { return _originID; } + + void setOriginID(int originID) { _originID = originID; } + /// Returns the unique remote ID for this object, or zero if this is a local object. int getRemoteID() const { return _remoteID; } void setRemoteID(int remoteID) { _remoteID = remoteID; } + /// Returns the remote origin ID for this object, or zero if this is a local object. + int getRemoteOriginID() const { return _remoteOriginID; } + + void setRemoteOriginID(int remoteOriginID) { _remoteOriginID = remoteOriginID; } + int getReferenceCount() const { return _referenceCount.load(); } void incrementReferenceCount(); void decrementReferenceCount(); /// Creates a new clone of this object. - /// \param withID if true, give the clone the same ID as this object - virtual SharedObject* clone(bool withID = false) const; + /// \param withID if true, give the clone the same origin ID as this object + /// \target if non-NULL, a target object to populate (as opposed to creating a new instance of this object's class) + virtual SharedObject* clone(bool withID = false, SharedObject* target = NULL) const; /// Tests this object for equality with another. - virtual bool equals(const SharedObject* other) const; + /// \param sharedAncestry if true and the classes of the objects differ, compare their shared ancestry (assuming that + /// this is an instance of a superclass of the other object's class) rather than simply returning false. + virtual bool equals(const SharedObject* other, bool sharedAncestry = false) const; // Dumps the contents of this object to the debug output. virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const; private: - void setID(int id); - int _id; + int _originID; int _remoteID; + int _remoteOriginID; QAtomicInt _referenceCount; static int _lastID;