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;
}
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) {
_sharedObjectStreamer.removePersistentID(reference);
reference->disconnect(this);
@ -227,7 +227,7 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
if (!it.value()) {
continue;
}
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteID()];
QPointer<SharedObject>& 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<SharedObject> reference = _sharedObjectReferences.value(object->getID());
*this << object->getOriginID();
QPointer<SharedObject> 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<SharedObject> reference = _sharedObjectReferences.value(id);
int originID;
*this >> originID;
QPointer<SharedObject> reference = _sharedObjectReferences.value(originID);
QPointer<SharedObject>& 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<SharedObject*>(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<SharedObject*>(pointer.data());
@ -893,7 +916,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
void Bitstream::clearSharedObject(QObject* object) {
SharedObject* sharedObject = static_cast<SharedObject*>(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");
}

View file

@ -294,6 +294,9 @@ public:
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 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 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>>(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>>(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) {
int addedOrRemoved = 0;
foreach (const T& element, value) {
@ -600,6 +636,27 @@ template<class T> inline Bitstream& Bitstream::operator>>(QList<T>& list) {
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) {
*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 T> 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<T>(), reference.value<T>()); }
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 {
out.writeRawDelta(value.value<T>(), reference.value<T>()); }
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.
@ -858,6 +923,22 @@ public:
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.
template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > {
public:
@ -940,6 +1021,13 @@ template<class T> int registerStreamableMetaType() {
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).
#define STREAMABLE public: \
static const int Type; \

View file

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

View file

@ -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<SharedObject*>(metaObject->newInstance());
if (!target) {
target = static_cast<SharedObject*>(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<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()) {
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<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;

View file

@ -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;