Ported over fixes that I made when working on delta-encoding for avatars.

This commit is contained in:
Andrzej Kapolka 2014-06-02 15:16:08 -07:00
parent 6f5d2ba233
commit 6db385de7a
5 changed files with 184 additions and 32 deletions

View file

@ -193,7 +193,7 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) {
continue; continue;
} }
connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*)));
QPointer<SharedObject>& reference = _sharedObjectReferences[it.key()->getID()]; QPointer<SharedObject>& reference = _sharedObjectReferences[it.key()->getOriginID()];
if (reference) { if (reference) {
_sharedObjectStreamer.removePersistentID(reference); _sharedObjectStreamer.removePersistentID(reference);
reference->disconnect(this); reference->disconnect(this);
@ -227,7 +227,7 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
if (!it.value()) { if (!it.value()) {
continue; continue;
} }
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteID()]; QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()];
if (reference) { if (reference) {
_sharedObjectStreamer.removePersistentValue(reference.data()); _sharedObjectStreamer.removePersistentValue(reference.data());
} }
@ -411,6 +411,10 @@ Bitstream& Bitstream::operator>>(QUrl& url) {
} }
Bitstream& Bitstream::operator<<(const QVariant& value) { Bitstream& Bitstream::operator<<(const QVariant& value) {
if (!value.isValid()) {
_typeStreamerStreamer << NULL;
return *this;
}
const TypeStreamer* streamer = getTypeStreamers().value(value.userType()); const TypeStreamer* streamer = getTypeStreamers().value(value.userType());
if (streamer) { if (streamer) {
_typeStreamerStreamer << streamer; _typeStreamerStreamer << streamer;
@ -424,7 +428,11 @@ Bitstream& Bitstream::operator<<(const QVariant& value) {
Bitstream& Bitstream::operator>>(QVariant& value) { Bitstream& Bitstream::operator>>(QVariant& value) {
TypeReader reader; TypeReader reader;
_typeStreamerStreamer >> reader; _typeStreamerStreamer >> reader;
value = reader.read(*this); if (reader.getTypeName().isEmpty()) {
value = QVariant();
} else {
value = reader.read(*this);
}
return *this; return *this;
} }
@ -656,6 +664,10 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) {
} }
Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
if (!streamer) {
*this << QByteArray();
return *this;
}
const char* typeName = QMetaType::typeName(streamer->getType()); const char* typeName = QMetaType::typeName(streamer->getType());
*this << QByteArray::fromRawData(typeName, strlen(typeName)); *this << QByteArray::fromRawData(typeName, strlen(typeName));
if (_metadataType == NO_METADATA) { if (_metadataType == NO_METADATA) {
@ -702,6 +714,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
Bitstream& Bitstream::operator>(TypeReader& reader) { Bitstream& Bitstream::operator>(TypeReader& reader) {
QByteArray typeName; QByteArray typeName;
*this >> typeName; *this >> typeName;
if (typeName.isEmpty()) {
reader = TypeReader();
return *this;
}
const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName);
if (!streamer) { if (!streamer) {
streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
@ -847,9 +863,10 @@ Bitstream& Bitstream::operator<(const SharedObjectPointer& object) {
return *this << (int)0; return *this << (int)0;
} }
*this << object->getID(); *this << object->getID();
QPointer<SharedObject> reference = _sharedObjectReferences.value(object->getID()); *this << object->getOriginID();
QPointer<SharedObject> reference = _sharedObjectReferences.value(object->getOriginID());
if (reference) { if (reference) {
writeRawDelta((QObject*)object.data(), (QObject*)reference.data()); writeRawDelta((const QObject*)object.data(), (const QObject*)reference.data());
} else { } else {
*this << (QObject*)object.data(); *this << (QObject*)object.data();
} }
@ -863,7 +880,9 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
object = SharedObjectPointer(); object = SharedObjectPointer();
return *this; return *this;
} }
QPointer<SharedObject> reference = _sharedObjectReferences.value(id); int originID;
*this >> originID;
QPointer<SharedObject> reference = _sharedObjectReferences.value(originID);
QPointer<SharedObject>& pointer = _weakSharedObjectHash[id]; QPointer<SharedObject>& pointer = _weakSharedObjectHash[id];
if (pointer) { if (pointer) {
ObjectReader objectReader; ObjectReader objectReader;
@ -876,15 +895,19 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
} else { } else {
QObject* rawObject; QObject* rawObject;
if (reference) { if (reference) {
readRawDelta(rawObject, (QObject*)reference.data()); readRawDelta(rawObject, (const QObject*)reference.data());
} else { } else {
*this >> rawObject; *this >> rawObject;
} }
pointer = static_cast<SharedObject*>(rawObject); pointer = static_cast<SharedObject*>(rawObject);
if (pointer) { if (pointer) {
if (reference) {
pointer->setOriginID(reference->getOriginID());
}
pointer->setRemoteID(id); pointer->setRemoteID(id);
pointer->setRemoteOriginID(originID);
} else { } else {
qDebug() << "Null object" << pointer << reference; qDebug() << "Null object" << pointer << reference << id;
} }
} }
object = static_cast<SharedObject*>(pointer.data()); object = static_cast<SharedObject*>(pointer.data());
@ -893,7 +916,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
void Bitstream::clearSharedObject(QObject* object) { void Bitstream::clearSharedObject(QObject* object) {
SharedObject* sharedObject = static_cast<SharedObject*>(object); SharedObject* sharedObject = static_cast<SharedObject*>(object);
_sharedObjectReferences.remove(sharedObject->getID()); _sharedObjectReferences.remove(sharedObject->getOriginID());
int id = _sharedObjectStreamer.takePersistentID(sharedObject); int id = _sharedObjectStreamer.takePersistentID(sharedObject);
if (id != 0) { if (id != 0) {
emit sharedObjectCleared(id); emit sharedObjectCleared(id);
@ -1099,6 +1122,10 @@ uint qHash(const TypeReader& typeReader, uint seed) {
return qHash(typeReader.getTypeName(), seed); return qHash(typeReader.getTypeName(), seed);
} }
QDebug& operator<<(QDebug& debug, const TypeReader& typeReader) {
return debug << typeReader.getTypeName();
}
FieldReader::FieldReader(const TypeReader& reader, int index) : FieldReader::FieldReader(const TypeReader& reader, int index) :
_reader(reader), _reader(reader),
_index(index) { _index(index) {
@ -1152,6 +1179,10 @@ uint qHash(const ObjectReader& objectReader, uint seed) {
return qHash(objectReader.getClassName(), 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) : PropertyReader::PropertyReader(const TypeReader& reader, const QMetaProperty& property) :
_reader(reader), _reader(reader),
_property(property) { _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 { void TypeStreamer::setValue(QVariant& object, int index, const QVariant& value) const {
// nothing by default // 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");
}

View file

@ -294,6 +294,9 @@ public:
template<class T> void writeRawDelta(const QList<T>& value, const QList<T>& reference); template<class T> void writeRawDelta(const QList<T>& value, const QList<T>& reference);
template<class T> void readRawDelta(QList<T>& value, const QList<T>& reference); template<class T> void readRawDelta(QList<T>& value, const QList<T>& reference);
template<class T> void writeRawDelta(const QVector<T>& value, const QVector<T>& reference);
template<class T> void readRawDelta(QVector<T>& value, const QVector<T>& reference);
template<class T> void writeRawDelta(const QSet<T>& value, const QSet<T>& reference); template<class T> void writeRawDelta(const QSet<T>& value, const QSet<T>& reference);
template<class T> void readRawDelta(QSet<T>& value, const QSet<T>& reference); template<class T> void readRawDelta(QSet<T>& value, const QSet<T>& reference);
@ -339,6 +342,9 @@ public:
template<class T> Bitstream& operator<<(const QList<T>& list); template<class T> Bitstream& operator<<(const QList<T>& list);
template<class T> Bitstream& operator>>(QList<T>& list); template<class T> Bitstream& operator>>(QList<T>& list);
template<class T> Bitstream& operator<<(const QVector<T>& list);
template<class T> Bitstream& operator>>(QVector<T>& list);
template<class T> Bitstream& operator<<(const QSet<T>& set); template<class T> Bitstream& operator<<(const QSet<T>& set);
template<class T> Bitstream& operator>>(QSet<T>& set); template<class T> Bitstream& operator>>(QSet<T>& set);
@ -472,6 +478,36 @@ template<class T> inline void Bitstream::readRawDelta(QList<T>& value, const QLi
} }
} }
template<class T> inline void Bitstream::writeRawDelta(const QVector<T>& value, const QVector<T>& 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<class T> inline void Bitstream::readRawDelta(QVector<T>& value, const QVector<T>& 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<class T> inline void Bitstream::writeRawDelta(const QSet<T>& value, const QSet<T>& reference) { template<class T> inline void Bitstream::writeRawDelta(const QSet<T>& value, const QSet<T>& reference) {
int addedOrRemoved = 0; int addedOrRemoved = 0;
foreach (const T& element, value) { foreach (const T& element, value) {
@ -600,6 +636,27 @@ template<class T> inline Bitstream& Bitstream::operator>>(QList<T>& list) {
return *this; return *this;
} }
template<class T> inline Bitstream& Bitstream::operator<<(const QVector<T>& vector) {
*this << vector.size();
foreach (const T& entry, vector) {
*this << entry;
}
return *this;
}
template<class T> inline Bitstream& Bitstream::operator>>(QVector<T>& 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<class T> inline Bitstream& Bitstream::operator<<(const QSet<T>& set) { template<class T> inline Bitstream& Bitstream::operator<<(const QSet<T>& set) {
*this << set.size(); *this << set.size();
foreach (const T& entry, set) { foreach (const T& entry, set) {
@ -683,6 +740,8 @@ private:
uint qHash(const TypeReader& typeReader, uint seed = 0); 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. /// Contains the information required to read a metatype field from the stream and apply it.
class FieldReader { class FieldReader {
public: public:
@ -726,6 +785,8 @@ private:
uint qHash(const ObjectReader& objectReader, uint seed = 0); 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. /// Contains the information required to read an object property from the stream and apply it.
class PropertyReader { class PropertyReader {
public: public:
@ -808,6 +869,10 @@ private:
int _type; int _type;
}; };
QDebug& operator<<(QDebug& debug, const TypeStreamer* typeStreamer);
QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject);
/// A streamer that works with Bitstream's operators. /// A streamer that works with Bitstream's operators.
template<class T> class SimpleTypeStreamer : public TypeStreamer { template<class T> class SimpleTypeStreamer : public TypeStreamer {
public: public:
@ -818,11 +883,11 @@ public:
virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
out.writeDelta(value.value<T>(), reference.value<T>()); } out.writeDelta(value.value<T>(), reference.value<T>()); }
virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
in.readDelta(*static_cast<T*>(value.data()), reference.value<T>()); } T rawValue; in.readDelta(rawValue, reference.value<T>()); value = QVariant::fromValue(rawValue); }
virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const {
out.writeRawDelta(value.value<T>(), reference.value<T>()); } out.writeRawDelta(value.value<T>(), reference.value<T>()); }
virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const {
in.readRawDelta(*static_cast<T*>(value.data()), reference.value<T>()); } T rawValue; in.readRawDelta(rawValue, reference.value<T>()); value = QVariant::fromValue(rawValue); }
}; };
/// A streamer for types compiled by mtc. /// A streamer for types compiled by mtc.
@ -858,6 +923,22 @@ public:
static_cast<QList<T>*>(object.data())->replace(index, value.value<T>()); } static_cast<QList<T>*>(object.data())->replace(index, value.value<T>()); }
}; };
/// A streamer for vector types.
template<class T> class CollectionTypeStreamer<QVector<T> > : public SimpleTypeStreamer<QVector<T> > {
public:
virtual TypeReader::Type getReaderType() const { return TypeReader::LIST_TYPE; }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
virtual void insert(QVariant& object, const QVariant& value) const {
static_cast<QVector<T>*>(object.data())->append(value.value<T>()); }
virtual void prune(QVariant& object, int size) const {
QVector<T>* list = static_cast<QVector<T>*>(object.data()); list->erase(list->begin() + size, list->end()); }
virtual QVariant getValue(const QVariant& object, int index) const {
return QVariant::fromValue(static_cast<const QVector<T>*>(object.constData())->at(index)); }
virtual void setValue(QVariant& object, int index, const QVariant& value) const {
static_cast<QVector<T>*>(object.data())->replace(index, value.value<T>()); }
};
/// A streamer for set types. /// A streamer for set types.
template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > { template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > {
public: public:
@ -940,6 +1021,13 @@ template<class T> int registerStreamableMetaType() {
return type; return type;
} }
/// Registers a collection type and its streamer.
template<class T> int registerCollectionMetaType() {
int type = qRegisterMetaType<T>();
Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer<T>());
return type;
}
/// Flags a class as streamable (use as you would Q_OBJECT). /// Flags a class as streamable (use as you would Q_OBJECT).
#define STREAMABLE public: \ #define STREAMABLE public: \
static const int Type; \ static const int Type; \

View file

@ -19,7 +19,7 @@
#include <QSet> #include <QSet>
#include <QVector> #include <QVector>
#include "Bitstream.h" #include "AttributeRegistry.h"
class ReliableChannel; class ReliableChannel;

View file

@ -23,7 +23,9 @@ REGISTER_META_OBJECT(SharedObject)
SharedObject::SharedObject() : SharedObject::SharedObject() :
_id(++_lastID), _id(++_lastID),
_remoteID(0) { _originID(_id),
_remoteID(0),
_remoteOriginID(0) {
_weakHash.insert(_id, this); _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 // default behavior is to make a copy using the no-arg constructor and copy the stored properties
const QMetaObject* metaObject = this->metaObject(); const QMetaObject* metaObject = this->metaObject();
SharedObject* newObject = static_cast<SharedObject*>(metaObject->newInstance()); if (!target) {
target = static_cast<SharedObject*>(metaObject->newInstance());
}
for (int i = 0; i < metaObject->propertyCount(); i++) { for (int i = 0; i < metaObject->propertyCount(); i++) {
QMetaProperty property = metaObject->property(i); QMetaProperty property = metaObject->property(i);
if (property.isStored()) { if (property.isStored()) {
property.write(newObject, property.read(this)); if (property.userType() == qMetaTypeId<SharedObjectPointer>()) {
SharedObject* value = property.read(this).value<SharedObjectPointer>().data();
property.write(target, QVariant::fromValue(value ? value->clone(withID) : value));
} else {
property.write(target, property.read(this));
}
} }
} }
foreach (const QByteArray& propertyName, dynamicPropertyNames()) { foreach (const QByteArray& propertyName, dynamicPropertyNames()) {
newObject->setProperty(propertyName, property(propertyName)); target->setProperty(propertyName, property(propertyName));
} }
if (withID) { 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) { if (!other) {
return false; return false;
} }
@ -67,7 +76,7 @@ bool SharedObject::equals(const SharedObject* other) const {
} }
// default behavior is to compare the properties // default behavior is to compare the properties
const QMetaObject* metaObject = this->metaObject(); const QMetaObject* metaObject = this->metaObject();
if (metaObject != other->metaObject()) { if (metaObject != other->metaObject() && !sharedAncestry) {
return false; return false;
} }
for (int i = 0; i < metaObject->propertyCount(); i++) { for (int i = 0; i < metaObject->propertyCount(); i++) {
@ -92,13 +101,15 @@ void SharedObject::dump(QDebug debug) const {
debug << this; debug << this;
const QMetaObject* metaObject = this->metaObject(); const QMetaObject* metaObject = this->metaObject();
for (int i = 0; i < metaObject->propertyCount(); i++) { 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<QByteArray> 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; int SharedObject::_lastID = 0;

View file

@ -41,31 +41,44 @@ public:
/// Returns the unique local ID for this object. /// Returns the unique local ID for this object.
int getID() const { return _id; } 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. /// Returns the unique remote ID for this object, or zero if this is a local object.
int getRemoteID() const { return _remoteID; } int getRemoteID() const { return _remoteID; }
void setRemoteID(int remoteID) { _remoteID = 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(); } int getReferenceCount() const { return _referenceCount.load(); }
void incrementReferenceCount(); void incrementReferenceCount();
void decrementReferenceCount(); void decrementReferenceCount();
/// Creates a new clone of this object. /// Creates a new clone of this object.
/// \param withID if true, give the clone the same ID as this object /// \param withID if true, give the clone the same origin ID as this object
virtual SharedObject* clone(bool withID = false) const; /// \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. /// 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. // Dumps the contents of this object to the debug output.
virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const; virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const;
private: private:
void setID(int id);
int _id; int _id;
int _originID;
int _remoteID; int _remoteID;
int _remoteOriginID;
QAtomicInt _referenceCount; QAtomicInt _referenceCount;
static int _lastID; static int _lastID;