mirror of
https://github.com/lubosz/overte.git
synced 2025-04-13 03:53:09 +02:00
Working on delta streaming for collections.
This commit is contained in:
parent
20e9572f60
commit
9c2f6ab2e5
3 changed files with 312 additions and 55 deletions
|
@ -577,16 +577,17 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
|
|||
if (_metadataType == NO_METADATA) {
|
||||
return *this;
|
||||
}
|
||||
TypeStreamer::Category category = streamer->getCategory();
|
||||
*this << (int)category;
|
||||
switch (category) {
|
||||
case TypeStreamer::SIMPLE_CATEGORY:
|
||||
TypeReader::Type type = streamer->getReaderType();
|
||||
*this << (int)type;
|
||||
switch (type) {
|
||||
case TypeReader::SIMPLE_TYPE:
|
||||
return *this;
|
||||
|
||||
case TypeStreamer::LIST_CATEGORY:
|
||||
case TypeReader::LIST_TYPE:
|
||||
case TypeReader::SET_TYPE:
|
||||
return *this << streamer->getValueStreamer();
|
||||
|
||||
case TypeStreamer::MAP_CATEGORY:
|
||||
case TypeReader::MAP_TYPE:
|
||||
return *this << streamer->getKeyStreamer() << streamer->getValueStreamer();
|
||||
|
||||
default:
|
||||
|
@ -628,35 +629,36 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
|
|||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
}
|
||||
int category;
|
||||
*this >> category;
|
||||
switch (category) {
|
||||
case TypeStreamer::SIMPLE_CATEGORY:
|
||||
int type;
|
||||
*this >> type;
|
||||
switch (type) {
|
||||
case TypeReader::SIMPLE_TYPE:
|
||||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
|
||||
case TypeStreamer::LIST_CATEGORY: {
|
||||
case TypeReader::LIST_TYPE:
|
||||
case TypeReader::SET_TYPE: {
|
||||
TypeReader valueReader;
|
||||
*this >> valueReader;
|
||||
if (streamer && streamer->getCategory() == TypeStreamer::LIST_CATEGORY &&
|
||||
if (streamer && streamer->getReaderType() == type &&
|
||||
valueReader.matchesExactly(streamer->getValueStreamer())) {
|
||||
reader = TypeReader(typeName, streamer);
|
||||
} else {
|
||||
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(),
|
||||
reader = TypeReader(typeName, streamer, false, (TypeReader::Type)type, TypeReaderPointer(),
|
||||
TypeReaderPointer(new TypeReader(valueReader)));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
case TypeStreamer::MAP_CATEGORY: {
|
||||
case TypeReader::MAP_TYPE: {
|
||||
TypeReader keyReader, valueReader;
|
||||
*this >> keyReader >> valueReader;
|
||||
if (streamer && streamer->getCategory() == TypeStreamer::MAP_CATEGORY &&
|
||||
if (streamer && streamer->getReaderType() == TypeReader::MAP_TYPE &&
|
||||
keyReader.matchesExactly(streamer->getKeyStreamer()) &&
|
||||
valueReader.matchesExactly(streamer->getValueStreamer())) {
|
||||
reader = TypeReader(typeName, streamer);
|
||||
} else {
|
||||
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(new TypeReader(keyReader)),
|
||||
TypeReaderPointer(new TypeReader(valueReader)));
|
||||
reader = TypeReader(typeName, streamer, false, TypeReader::MAP_TYPE,
|
||||
TypeReaderPointer(new TypeReader(keyReader)), TypeReaderPointer(new TypeReader(valueReader)));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -714,20 +716,23 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
|
|||
// if all fields are the same type and in the right order, we can use the (more efficient) default streamer
|
||||
const QVector<MetaField>& localFields = streamer->getMetaFields();
|
||||
if (fieldCount != localFields.size()) {
|
||||
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(), TypeReaderPointer(), fields);
|
||||
reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE,
|
||||
TypeReaderPointer(), TypeReaderPointer(), 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, false, TypeReaderPointer(), TypeReaderPointer(), fields);
|
||||
reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE,
|
||||
TypeReaderPointer(), TypeReaderPointer(), fields);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
reader = TypeReader(typeName, streamer);
|
||||
return *this;
|
||||
}
|
||||
reader = TypeReader(typeName, streamer, false, TypeReaderPointer(), TypeReaderPointer(), fields);
|
||||
reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE,
|
||||
TypeReaderPointer(), TypeReaderPointer(), fields);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -823,11 +828,12 @@ QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObj
|
|||
return propertyReaders;
|
||||
}
|
||||
|
||||
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch,
|
||||
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch, Type type,
|
||||
const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader, const QVector<FieldReader>& fields) :
|
||||
_typeName(typeName),
|
||||
_streamer(streamer),
|
||||
_exactMatch(exactMatch),
|
||||
_type(type),
|
||||
_keyReader(keyReader),
|
||||
_valueReader(valueReader),
|
||||
_fields(fields) {
|
||||
|
@ -838,10 +844,28 @@ QVariant TypeReader::read(Bitstream& in) const {
|
|||
return _streamer->read(in);
|
||||
}
|
||||
QVariant object = _streamer ? QVariant(_streamer->getType(), 0) : QVariant();
|
||||
if (_valueReader) {
|
||||
int size;
|
||||
in >> size;
|
||||
if (_keyReader) {
|
||||
switch (_type) {
|
||||
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);
|
||||
|
@ -849,18 +873,10 @@ QVariant TypeReader::read(Bitstream& in) const {
|
|||
_streamer->insert(object, key, value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < size; i++) {
|
||||
QVariant value = _valueReader->read(in);
|
||||
if (_streamer) {
|
||||
_streamer->insert(object, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach (const FieldReader& field, _fields) {
|
||||
field.read(in, _streamer, object);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
@ -870,13 +886,67 @@ void TypeReader::readDelta(Bitstream& in, QVariant& object, const QVariant& refe
|
|||
_streamer->readDelta(in, object, reference);
|
||||
return;
|
||||
}
|
||||
if (_valueReader) {
|
||||
// TODO: collection deltas
|
||||
|
||||
} else {
|
||||
foreach (const FieldReader& field, _fields) {
|
||||
field.readDelta(in, _streamer, object, reference);
|
||||
}
|
||||
bool changed;
|
||||
in >> changed;
|
||||
if (!changed) {
|
||||
object = reference;
|
||||
return;
|
||||
}
|
||||
switch (_type) {
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -958,8 +1028,8 @@ void TypeStreamer::setField(int index, QVariant& object, const QVariant& value)
|
|||
// nothing by default
|
||||
}
|
||||
|
||||
TypeStreamer::Category TypeStreamer::getCategory() const {
|
||||
return SIMPLE_CATEGORY;
|
||||
TypeReader::Type TypeStreamer::getReaderType() const {
|
||||
return TypeReader::SIMPLE_TYPE;
|
||||
}
|
||||
|
||||
const TypeStreamer* TypeStreamer::getKeyStreamer() const {
|
||||
|
@ -977,3 +1047,7 @@ void TypeStreamer::insert(QVariant& object, const QVariant& element) const {
|
|||
void TypeStreamer::insert(QVariant& object, const QVariant& key, const QVariant& value) const {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
bool TypeStreamer::remove(QVariant& object, const QVariant& key) const {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -271,9 +271,15 @@ public:
|
|||
template<class T> void writeDelta(const T& value, const T& reference);
|
||||
template<class T> void readDelta(T& value, const T& reference);
|
||||
|
||||
template<class T> void writeDelta(const QList<T>& value, const QList<T>& reference);
|
||||
template<class T> void readDelta(QList<T>& value, const QList<T>& reference);
|
||||
|
||||
template<class T> void writeDelta(const QSet<T>& value, const QSet<T>& reference);
|
||||
template<class T> void readDelta(QSet<T>& value, const QSet<T>& reference);
|
||||
|
||||
template<class K, class V> void writeDelta(const QHash<K, V>& value, const QHash<K, V>& reference);
|
||||
template<class K, class V> void readDelta(QHash<K, V>& value, const QHash<K, V>& reference);
|
||||
|
||||
Bitstream& operator<<(bool value);
|
||||
Bitstream& operator>>(bool& value);
|
||||
|
||||
|
@ -403,12 +409,171 @@ template<class T> inline void Bitstream::readDelta(T& value, const T& reference)
|
|||
}
|
||||
}
|
||||
|
||||
template<class T> inline void Bitstream::writeDelta(const QList<T>& value, const QList<T>& reference) {
|
||||
if (value == reference) {
|
||||
*this << false;
|
||||
return;
|
||||
}
|
||||
*this << true;
|
||||
*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::readDelta(QList<T>& value, const QList<T>& reference) {
|
||||
value = reference;
|
||||
bool changed;
|
||||
*this >> changed;
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
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::writeDelta(const QSet<T>& value, const QSet<T>& reference) {
|
||||
|
||||
if (value == reference) {
|
||||
*this << false;
|
||||
return;
|
||||
}
|
||||
*this << true;
|
||||
int addedOrRemoved = 0;
|
||||
foreach (const T& element, value) {
|
||||
if (!reference.contains(element)) {
|
||||
addedOrRemoved++;
|
||||
}
|
||||
}
|
||||
foreach (const T& element, reference) {
|
||||
if (!value.contains(element)) {
|
||||
addedOrRemoved++;
|
||||
}
|
||||
}
|
||||
*this << addedOrRemoved;
|
||||
foreach (const T& element, value) {
|
||||
if (!reference.contains(element)) {
|
||||
*this << element;
|
||||
}
|
||||
}
|
||||
foreach (const T& element, reference) {
|
||||
if (!value.contains(element)) {
|
||||
*this << element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> inline void Bitstream::readDelta(QSet<T>& value, const QSet<T>& reference) {
|
||||
|
||||
value = reference;
|
||||
bool changed;
|
||||
*this >> changed;
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
int addedOrRemoved;
|
||||
*this >> addedOrRemoved;
|
||||
for (int i = 0; i < addedOrRemoved; i++) {
|
||||
T element;
|
||||
*this >> element;
|
||||
if (!value.remove(element)) {
|
||||
value.insert(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class K, class V> inline void Bitstream::writeDelta(const QHash<K, V>& value, const QHash<K, V>& reference) {
|
||||
if (value == reference) {
|
||||
*this << false;
|
||||
return;
|
||||
}
|
||||
*this << true;
|
||||
int added = 0;
|
||||
int modified = 0;
|
||||
for (typename QHash<K, V>::const_iterator it = value.constBegin(); it != value.constEnd(); it++) {
|
||||
typename QHash<K, V>::const_iterator previous = reference.find(it.key());
|
||||
if (previous == reference.constEnd()) {
|
||||
added++;
|
||||
} else if (previous.value() != it.value()) {
|
||||
modified++;
|
||||
}
|
||||
}
|
||||
*this << added;
|
||||
for (typename QHash<K, V>::const_iterator it = value.constBegin(); it != value.constEnd(); it++) {
|
||||
if (!reference.contains(it.key())) {
|
||||
*this << it.key();
|
||||
*this << it.value();
|
||||
}
|
||||
}
|
||||
*this << modified;
|
||||
for (typename QHash<K, V>::const_iterator it = value.constBegin(); it != value.constEnd(); it++) {
|
||||
typename QHash<K, V>::const_iterator previous = reference.find(it.key());
|
||||
if (previous != reference.constEnd() && previous.value() != it.value()) {
|
||||
*this << it.key();
|
||||
writeDelta(it.value(), previous.value());
|
||||
}
|
||||
}
|
||||
int removed = 0;
|
||||
for (typename QHash<K, V>::const_iterator it = reference.constBegin(); it != reference.constEnd(); it++) {
|
||||
if (!value.contains(it.key())) {
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
*this << removed;
|
||||
for (typename QHash<K, V>::const_iterator it = reference.constBegin(); it != reference.constEnd(); it++) {
|
||||
if (!value.contains(it.key())) {
|
||||
*this << it.key();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class K, class V> inline void Bitstream::readDelta(QHash<K, V>& value, const QHash<K, V>& reference) {
|
||||
value = reference;
|
||||
bool changed;
|
||||
*this >> changed;
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
int added;
|
||||
*this >> added;
|
||||
for (int i = 0; i < added; i++) {
|
||||
K key;
|
||||
V mapping;
|
||||
*this >> key >> mapping;
|
||||
value.insert(key, mapping);
|
||||
}
|
||||
int modified;
|
||||
*this >> modified;
|
||||
for (int i = 0; i < modified; i++) {
|
||||
K key;
|
||||
*this >> key;
|
||||
V& mapping = value[key];
|
||||
V newMapping;
|
||||
readDelta(newMapping, mapping);
|
||||
mapping = newMapping;
|
||||
}
|
||||
int removed;
|
||||
*this >> removed;
|
||||
for (int i = 0; i < removed; i++) {
|
||||
K key;
|
||||
*this >> key;
|
||||
value.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T> inline Bitstream& Bitstream::operator<<(const QList<T>& list) {
|
||||
|
@ -483,8 +648,11 @@ typedef QSharedPointer<TypeReader> TypeReaderPointer;
|
|||
class TypeReader {
|
||||
public:
|
||||
|
||||
enum Type { SIMPLE_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE };
|
||||
|
||||
TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true,
|
||||
const TypeReaderPointer& keyReader = TypeReaderPointer(), const TypeReaderPointer& valueReader = TypeReaderPointer(),
|
||||
Type type = SIMPLE_TYPE, const TypeReaderPointer& keyReader = TypeReaderPointer(),
|
||||
const TypeReaderPointer& valueReader = TypeReaderPointer(),
|
||||
const QVector<FieldReader>& fields = QVector<FieldReader>());
|
||||
|
||||
const QByteArray& getTypeName() const { return _typeName; }
|
||||
|
@ -503,6 +671,7 @@ private:
|
|||
QByteArray _typeName;
|
||||
const TypeStreamer* _streamer;
|
||||
bool _exactMatch;
|
||||
Type _type;
|
||||
TypeReaderPointer _keyReader;
|
||||
TypeReaderPointer _valueReader;
|
||||
QVector<FieldReader> _fields;
|
||||
|
@ -607,15 +776,14 @@ public:
|
|||
virtual int getFieldIndex(const QByteArray& name) const;
|
||||
virtual void setField(int index, QVariant& object, const QVariant& value) const;
|
||||
|
||||
enum Category { SIMPLE_CATEGORY, STREAMABLE_CATEGORY, LIST_CATEGORY, MAP_CATEGORY };
|
||||
|
||||
virtual Category getCategory() const;
|
||||
virtual TypeReader::Type getReaderType() const;
|
||||
|
||||
virtual const TypeStreamer* getKeyStreamer() const;
|
||||
virtual const TypeStreamer* getValueStreamer() const;
|
||||
|
||||
virtual void insert(QVariant& object, const QVariant& value) const;
|
||||
virtual void insert(QVariant& object, const QVariant& key, const QVariant& value) const;
|
||||
virtual bool remove(QVariant& object, const QVariant& key) const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -638,7 +806,7 @@ public:
|
|||
template<class T> class StreamableTypeStreamer : public SimpleTypeStreamer<T> {
|
||||
public:
|
||||
|
||||
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::STREAMABLE_CATEGORY; }
|
||||
virtual TypeReader::Type getReaderType() const { return TypeReader::STREAMABLE_TYPE; }
|
||||
virtual const QVector<MetaField>& getMetaFields() const { return T::getMetaFields(); }
|
||||
virtual int getFieldIndex(const QByteArray& name) const { return T::getFieldIndex(name); }
|
||||
virtual void setField(int index, QVariant& object, const QVariant& value) const {
|
||||
|
@ -653,7 +821,7 @@ template<class T> class CollectionTypeStreamer : public SimpleTypeStreamer<T> {
|
|||
template<class T> class CollectionTypeStreamer<QList<T> > : public SimpleTypeStreamer<QList<T> > {
|
||||
public:
|
||||
|
||||
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; }
|
||||
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<QList<T>*>(object.data())->append(value.value<T>()); }
|
||||
|
@ -663,21 +831,25 @@ public:
|
|||
template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > {
|
||||
public:
|
||||
|
||||
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; }
|
||||
virtual TypeReader::Type getReaderType() const { return TypeReader::SET_TYPE; }
|
||||
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
|
||||
virtual void insert(QVariant& object, const QVariant& value) const {
|
||||
static_cast<QSet<T>*>(object.data())->insert(value.value<T>()); }
|
||||
virtual bool remove(QVariant& object, const QVariant& key) const {
|
||||
return static_cast<QSet<T>*>(object.data())->remove(key.value<T>()); }
|
||||
};
|
||||
|
||||
/// A streamer for hash types.
|
||||
template<class K, class V> class CollectionTypeStreamer<QHash<K, V> > : public SimpleTypeStreamer<QHash<K, V> > {
|
||||
public:
|
||||
|
||||
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::MAP_CATEGORY; }
|
||||
virtual TypeReader::Type getReaderType() const { return TypeReader::MAP_TYPE; }
|
||||
virtual const TypeStreamer* getKeyStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<K>()); }
|
||||
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<V>()); }
|
||||
virtual void insert(QVariant& object, const QVariant& key, const QVariant& value) const {
|
||||
static_cast<QHash<K, V>*>(object.data())->insert(key.value<K>(), value.value<V>()); }
|
||||
virtual bool remove(QVariant& object, const QVariant& key) const {
|
||||
return static_cast<QHash<K, V>*>(object.data())->remove(key.value<K>()); }
|
||||
};
|
||||
|
||||
/// Macro for registering simple type streamers.
|
||||
|
|
|
@ -173,6 +173,11 @@ void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
|||
out << "}\n";
|
||||
|
||||
out << "template<> void Bitstream::writeDelta(const " << name << "& value, const " << name << "& reference) {\n";
|
||||
out << " if (value == reference) {\n";
|
||||
out << " *this << false;\n";
|
||||
out << " return;\n";
|
||||
out << " }\n";
|
||||
out << " *this << true;\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " writeDelta(static_cast<const " << base << "&>(value), static_cast<const " <<
|
||||
base << "&>(reference));\n";
|
||||
|
@ -183,6 +188,12 @@ void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
|||
out << "}\n";
|
||||
|
||||
out << "template<> void Bitstream::readDelta(" << name << "& value, const " << name << "& reference) {\n";
|
||||
out << " bool changed;\n";
|
||||
out << " *this >> changed;\n";
|
||||
out << " if (!changed) {\n";
|
||||
out << " value = reference;\n";
|
||||
out << " return;\n";
|
||||
out << " }\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " readDelta(static_cast<" << base << "&>(value), static_cast<const " <<
|
||||
base << "&>(reference));\n";
|
||||
|
|
Loading…
Reference in a new issue