Midpoint on generic object streaming.

This commit is contained in:
Andrzej Kapolka 2014-06-12 16:22:32 -07:00
parent 056db4ba7d
commit b4bd774789
2 changed files with 274 additions and 41 deletions

View file

@ -1639,6 +1639,153 @@ QHash<const QMetaObject*, PropertyWriterVector> Bitstream::createPropertyWriters
return propertyWriters;
}
MappedObjectStreamer::MappedObjectStreamer(const QVector<StreamerPropertyPair>& properties) :
_properties(properties) {
}
const char* MappedObjectStreamer::getName() const {
return _metaObject->className();
}
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, QObject* object) const {
foreach (const StreamerPropertyPair& property, _properties) {
property.first->write(out, property.second.read(object));
}
}
void MappedObjectStreamer::writeDelta(Bitstream& out, QObject* object, 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 StreamerPropertyPair& property, _properties) {
QVariant value = property.first->read(in);
if (property.second.isValid() && object) {
property.second.write(object, value);
}
}
return object;
}
QObject* MappedObjectStreamer::readDelta(Bitstream& in, const QObject* reference, QObject* object) const {
if (!object && _metaObject) {
object = _metaObject->newInstance();
}
foreach (const StreamerPropertyPair& property, _properties) {
QVariant value;
property.first->readDelta(in, value, (property.second.isValid() && reference) ?
property.second.read(reference) : QVariant());
if (property.second.isValid() && object) {
property.second.write(object, value);
}
}
return object;
}
GenericObjectStreamer::GenericObjectStreamer(const QByteArray& name, const QVector<StreamerNamePair>& properties,
const QByteArray& hash) :
_name(name),
_properties(properties),
_hash(hash) {
_metaObject = &GenericSharedObject::staticMetaObject;
}
const char* GenericObjectStreamer::getName() const {
return _name.constData();
}
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<GenericObjectStreamer*>(this)->_hash = hash.result();
}
out.write(_hash.constData(), _hash.size() * BITS_IN_BYTE);
}
}
void GenericObjectStreamer::write(Bitstream& out, QObject* object) const {
const QVariantList& values = static_cast<GenericSharedObject*>(object)->getValues();
for (int i = 0; i < _properties.size(); i++) {
_properties.at(i).first->write(out, values.at(i));
}
}
void GenericObjectStreamer::writeDelta(Bitstream& out, QObject* object, QObject* reference) const {
for (int i = 0; i < _properties.size(); i++) {
_properties.at(i).first->writeDelta(out, static_cast<GenericSharedObject*>(object)->getValues().at(i), reference ?
static_cast<GenericSharedObject*>(reference)->getValues().at(i) : QVariant());
}
}
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<GenericSharedObject*>(object)->setValues(values);
return object;
}
QObject* GenericObjectStreamer::readDelta(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<const GenericSharedObject*>(reference)->getValues().at(i) : QVariant());
values.append(value);
}
static_cast<GenericSharedObject*>(object)->setValues(values);
return object;
}
ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject,
const PropertyReaderVector& properties) :
_className(className),
@ -1713,6 +1860,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() {
}
@ -2069,19 +2229,6 @@ TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const {
return ENUM_CATEGORY;
}
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;
}
const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const {
return value.value<GenericValue>().getStreamer().data();
}
MappedStreamableTypeStreamer::MappedStreamableTypeStreamer(const TypeStreamer* baseStreamer,
const QVector<StreamerIndexPair>& fields) :
_baseStreamer(baseStreamer),
@ -2334,3 +2481,7 @@ QVariant GenericMapTypeStreamer::read(Bitstream& in) const {
TypeStreamer::Category GenericMapTypeStreamer::getCategory() const {
return MAP_CATEGORY;
}
const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const {
return value.value<GenericValue>().getStreamer().data();
}

View file

@ -37,6 +37,7 @@ class AttributeValue;
class Bitstream;
class GenericValue;
class ObjectReader;
class ObjectStreamer;
class OwnedAttributeValue;
class PropertyReader;
class PropertyWriter;
@ -46,6 +47,8 @@ typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
typedef QPair<QByteArray, QByteArray> ScopeNamePair;
typedef QPair<QByteArray, int> NameIntPair;
typedef QSharedPointer<ObjectStreamer> ObjectStreamerPointer;
typedef QWeakPointer<ObjectStreamer> WeakObjectStreamerPointer;
typedef QSharedPointer<TypeStreamer> TypeStreamerPointer;
typedef QWeakPointer<TypeStreamer> WeakTypeStreamerPointer;
typedef QVector<PropertyReader> PropertyReaderVector;
@ -766,6 +769,68 @@ template<class K, class V> inline Bitstream& Bitstream::operator>>(QHash<K, V>&
return *this;
}
/// Contains the information required to stream an object.
class ObjectStreamer {
public:
virtual const char* getName() const = 0;
virtual void writeMetadata(Bitstream& out, bool full) const = 0;
virtual void write(Bitstream& out, QObject* object) const = 0;
virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const = 0;
virtual QObject* read(Bitstream& in, QObject* object = NULL) const = 0;
virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const = 0;
protected:
const QMetaObject* _metaObject;
ObjectStreamerPointer _self;
};
typedef QPair<TypeStreamerPointer, QMetaProperty> StreamerPropertyPair;
/// A streamer that maps to a local class.
class MappedObjectStreamer : public ObjectStreamer {
public:
MappedObjectStreamer(const QVector<StreamerPropertyPair>& properties);
virtual const char* getName() const;
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual void write(Bitstream& out, QObject* object) const;
virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const;
virtual QObject* read(Bitstream& in, QObject* object = NULL) const;
virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const;
private:
QVector<StreamerPropertyPair> _properties;
};
typedef QPair<TypeStreamerPointer, QByteArray> StreamerNamePair;
/// A streamer for generic objects.
class GenericObjectStreamer : public ObjectStreamer {
public:
GenericObjectStreamer(const QByteArray& name, const QVector<StreamerNamePair>& properties, const QByteArray& hash);
virtual const char* getName() const;
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual void write(Bitstream& out, QObject* object) const;
virtual void writeDelta(Bitstream& out, QObject* object, QObject* reference) const;
virtual QObject* read(Bitstream& in, QObject* object = NULL) const;
virtual QObject* readDelta(Bitstream& in, const QObject* reference, QObject* object = NULL) const;
private:
friend class Bitstream;
QByteArray _name;
WeakObjectStreamerPointer _weakSelf;
QVector<StreamerNamePair> _properties;
QByteArray _hash;
};
/// Contains the information required to read an object from the stream.
class ObjectReader {
public:
@ -849,6 +914,44 @@ 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:
@ -1012,32 +1115,6 @@ private:
QByteArray _hash;
};
/// 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)
/// A streamer class for generic values.
class GenericValueStreamer : public SimpleTypeStreamer<GenericValue> {
public:
virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const;
};
/// A streamer for types compiled by mtc.
template<class T> class StreamableTypeStreamer : public SimpleTypeStreamer<T> {
public:
@ -1068,8 +1145,6 @@ private:
QVector<StreamerIndexPair> _fields;
};
typedef QPair<TypeStreamerPointer, QByteArray> StreamerNamePair;
/// A streamer for generic enums.
class GenericStreamableTypeStreamer : public GenericTypeStreamer {
public:
@ -1238,6 +1313,13 @@ private:
TypeStreamerPointer _valueStreamer;
};
/// A streamer class for generic values.
class GenericValueStreamer : public SimpleTypeStreamer<GenericValue> {
public:
virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const;
};
/// Macro for registering simple type streamers.
#define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \
Bitstream::registerTypeStreamer(qMetaTypeId<X>(), new SimpleTypeStreamer<X>());