More work on generic containers.

This commit is contained in:
Andrzej Kapolka 2014-06-11 16:54:35 -07:00
parent c045595ccb
commit 6260d661f3
2 changed files with 301 additions and 62 deletions

View file

@ -45,7 +45,9 @@ static int metaObjectStreamer = Bitstream::registerTypeStreamer(qMetaTypeId<cons
new SimpleTypeStreamer<const QMetaObject*>());
static int genericValueStreamer = Bitstream::registerTypeStreamer(
qRegisterMetaType<GenericValue>(), new GenericTypeStreamer());
qRegisterMetaType<GenericValue>(), new GenericValueStreamer());
static int qVariantPairListMetaTypeId = qRegisterMetaType<QVariantPairList>();
IDStreamer::IDStreamer(Bitstream& stream) :
_stream(stream),
@ -1173,65 +1175,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
}
const char* typeName = streamer->getName();
*this << QByteArray::fromRawData(typeName, strlen(typeName));
if (_metadataType == NO_METADATA) {
return *this;
}
TypeStreamer::Category category = streamer->getCategory();
*this << (int)category;
switch (category) {
case TypeStreamer::SIMPLE_CATEGORY:
return *this;
case TypeStreamer::ENUM_CATEGORY: {
QMetaEnum metaEnum = streamer->getMetaEnum();
if (_metadataType == FULL_METADATA) {
*this << metaEnum.keyCount();
for (int i = 0; i < metaEnum.keyCount(); i++) {
*this << QByteArray::fromRawData(metaEnum.key(i), strlen(metaEnum.key(i)));
*this << metaEnum.value(i);
}
} else {
*this << streamer->getBits();
QCryptographicHash hash(QCryptographicHash::Md5);
for (int i = 0; i < metaEnum.keyCount(); i++) {
hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1);
qint32 value = metaEnum.value(i);
hash.addData((const char*)&value, sizeof(qint32));
}
QByteArray hashResult = hash.result();
write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE);
}
return *this;
}
case TypeStreamer::LIST_CATEGORY:
case TypeStreamer::SET_CATEGORY:
return *this << streamer->getValueStreamer();
case TypeStreamer::MAP_CATEGORY:
return *this << streamer->getKeyStreamer() << streamer->getValueStreamer();
default:
break; // fall through
}
// streamable type
const QVector<MetaField>& metaFields = streamer->getMetaFields();
*this << metaFields.size();
if (metaFields.isEmpty()) {
return *this;
}
QCryptographicHash hash(QCryptographicHash::Md5);
foreach (const MetaField& metaField, metaFields) {
_typeStreamerStreamer << metaField.getStreamer();
if (_metadataType == FULL_METADATA) {
*this << metaField.getName();
} else {
hash.addData(metaField.getName().constData(), metaField.getName().size() + 1);
}
}
if (_metadataType == HASH_METADATA) {
QByteArray hashResult = hash.result();
write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE);
}
if (_metadataType != NO_METADATA) {
*this << (int)streamer->getCategory();
streamer->writeMetadata(*this, _metadataType == FULL_METADATA);
}
return *this;
}
@ -1703,6 +1650,31 @@ const TypeStreamer* TypeStreamer::getStreamerToWrite(const QVariant& value) cons
return this;
}
void TypeStreamer::writeMetadata(Bitstream& out, bool full) const {
if (getCategory() != STREAMABLE_CATEGORY) {
return;
}
// streamable type
const QVector<MetaField>& metaFields = getMetaFields();
out << metaFields.size();
if (metaFields.isEmpty()) {
return;
}
QCryptographicHash hash(QCryptographicHash::Md5);
foreach (const MetaField& metaField, metaFields) {
out << metaField.getStreamer();
if (full) {
out << metaField.getName();
} else {
hash.addData(metaField.getName().constData(), metaField.getName().size() + 1);
}
}
if (!full) {
QByteArray hashResult = hash.result();
out.write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE);
}
}
bool TypeStreamer::equal(const QVariant& first, const QVariant& second) const {
return first == second;
}
@ -1842,6 +1814,27 @@ const char* EnumTypeStreamer::getName() const {
return _name.constData();
}
void EnumTypeStreamer::writeMetadata(Bitstream& out, bool full) const {
QMetaEnum metaEnum = getMetaEnum();
if (full) {
out << metaEnum.keyCount();
for (int i = 0; i < metaEnum.keyCount(); i++) {
out << QByteArray::fromRawData(metaEnum.key(i), strlen(metaEnum.key(i)));
out << metaEnum.value(i);
}
} else {
out << getBits();
QCryptographicHash hash(QCryptographicHash::Md5);
for (int i = 0; i < metaEnum.keyCount(); i++) {
hash.addData(metaEnum.key(i), strlen(metaEnum.key(i)) + 1);
qint32 value = metaEnum.value(i);
hash.addData((const char*)&value, sizeof(qint32));
}
QByteArray hashResult = hash.result();
out.write(hashResult.constData(), hashResult.size() * BITS_IN_BYTE);
}
}
TypeStreamer::Category EnumTypeStreamer::getCategory() const {
return ENUM_CATEGORY;
}
@ -1948,6 +1941,54 @@ void MappedEnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const
_baseStreamer->setEnumValue(object, value, _mappings);
}
GenericTypeStreamer::GenericTypeStreamer(const QByteArray& name) :
_name(name) {
}
const char* GenericTypeStreamer::getName() const {
return _name.constData();
}
GenericEnumTypeStreamer::GenericEnumTypeStreamer(const QByteArray& name, const QVector<NameIntPair>& values,
int bits, const QByteArray& hash) :
GenericTypeStreamer(name),
_values(values),
_bits(bits),
_hash(hash) {
_type = qMetaTypeId<int>();
}
void GenericEnumTypeStreamer::writeMetadata(Bitstream& out, bool full) const {
if (full) {
out << _values.size();
foreach (const NameIntPair& value, _values) {
out << value.first << value.second;
}
} else {
out << _bits;
if (_hash.isEmpty()) {
QCryptographicHash hash(QCryptographicHash::Md5);
foreach (const NameIntPair& value, _values) {
hash.addData(value.first.constData(), value.first.size() + 1);
qint32 intValue = value.second;
hash.addData((const char*)&intValue, sizeof(qint32));
}
const_cast<GenericEnumTypeStreamer*>(this)->_hash = hash.result();
}
out.write(_hash.constData(), _hash.size() * BITS_IN_BYTE);
}
}
void GenericEnumTypeStreamer::write(Bitstream& out, const QVariant& value) const {
int intValue = value.toInt();
out.write(&intValue, _bits);
}
TypeStreamer::Category GenericEnumTypeStreamer::getCategory() const {
return ENUM_CATEGORY;
}
GenericValue::GenericValue(const TypeStreamerPointer& streamer, const QVariant& value) :
_streamer(streamer),
_value(value) {
@ -1957,7 +1998,7 @@ bool GenericValue::operator==(const GenericValue& other) const {
return _streamer == other._streamer && _value == other._value;
}
const TypeStreamer* GenericTypeStreamer::getStreamerToWrite(const QVariant& value) const {
const TypeStreamer* GenericValueStreamer::getStreamerToWrite(const QVariant& value) const {
return value.value<GenericValue>().getStreamer().data();
}
@ -1990,6 +2031,46 @@ void MappedStreamableTypeStreamer::readRawDelta(Bitstream& in, QVariant& object,
}
}
GenericStreamableTypeStreamer::GenericStreamableTypeStreamer(const QByteArray& name,
const QVector<StreamerNamePair>& fields, const QByteArray& hash) :
GenericTypeStreamer(name),
_fields(fields),
_hash(hash) {
_type = qMetaTypeId<QVariantList>();
}
void GenericStreamableTypeStreamer::writeMetadata(Bitstream& out, bool full) const {
out << _fields.size();
foreach (const StreamerNamePair& field, _fields) {
out << field.first.data();
if (full) {
out << field.second;
}
}
if (!full) {
if (_hash.isEmpty()) {
QCryptographicHash hash(QCryptographicHash::Md5);
foreach (const StreamerNamePair& field, _fields) {
hash.addData(field.second.constData(), field.second.size() + 1);
}
const_cast<GenericStreamableTypeStreamer*>(this)->_hash = hash.result();
}
out.write(_hash.constData(), _hash.size() * BITS_IN_BYTE);
}
}
void GenericStreamableTypeStreamer::write(Bitstream& out, const QVariant& value) const {
QVariantList values = value.toList();
for (int i = 0; i < _fields.size(); i++) {
_fields.at(i).first->write(out, values.at(i));
}
}
TypeStreamer::Category GenericStreamableTypeStreamer::getCategory() const {
return STREAMABLE_CATEGORY;
}
MappedListTypeStreamer::MappedListTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) :
_baseStreamer(baseStreamer),
_valueStreamer(valueStreamer) {
@ -2024,6 +2105,29 @@ void MappedListTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const
}
}
GenericListTypeStreamer::GenericListTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer) :
GenericTypeStreamer(name),
_valueStreamer(valueStreamer) {
_type = qMetaTypeId<QVariantList>();
}
void GenericListTypeStreamer::writeMetadata(Bitstream& out, bool full) const {
out << _valueStreamer.data();
}
void GenericListTypeStreamer::write(Bitstream& out, const QVariant& value) const {
QVariantList values = value.toList();
out << values.size();
foreach (const QVariant& element, values) {
_valueStreamer->write(out, element);
}
}
TypeStreamer::Category GenericListTypeStreamer::getCategory() const {
return LIST_CATEGORY;
}
MappedSetTypeStreamer::MappedSetTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& valueStreamer) :
MappedListTypeStreamer(baseStreamer, valueStreamer) {
}
@ -2040,6 +2144,14 @@ void MappedSetTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const
}
}
GenericSetTypeStreamer::GenericSetTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer) :
GenericListTypeStreamer(name, valueStreamer) {
}
TypeStreamer::Category GenericSetTypeStreamer::getCategory() const {
return SET_CATEGORY;
}
MappedMapTypeStreamer::MappedMapTypeStreamer(const TypeStreamer* baseStreamer, const TypeStreamerPointer& keyStreamer,
const TypeStreamerPointer& valueStreamer) :
_baseStreamer(baseStreamer),
@ -2084,3 +2196,28 @@ void MappedMapTypeStreamer::readRawDelta(Bitstream& in, QVariant& object, const
}
}
GenericMapTypeStreamer::GenericMapTypeStreamer(const QByteArray& name, const TypeStreamerPointer& keyStreamer,
const TypeStreamerPointer& valueStreamer) :
GenericTypeStreamer(name),
_keyStreamer(keyStreamer),
_valueStreamer(valueStreamer) {
_type = qMetaTypeId<QVariantPairList>();
}
void GenericMapTypeStreamer::writeMetadata(Bitstream& out, bool full) const {
out << _keyStreamer.data() << _valueStreamer.data();
}
void GenericMapTypeStreamer::write(Bitstream& out, const QVariant& value) const {
QVariantPairList values = value.value<QVariantPairList>();
out << values.size();
foreach (const QVariantPair& pair, values) {
_keyStreamer->write(out, pair.first);
_valueStreamer->write(out, pair.second);
}
}
TypeStreamer::Category GenericMapTypeStreamer::getCategory() const {
return MAP_CATEGORY;
}

View file

@ -45,10 +45,16 @@ class TypeStreamer;
typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
typedef QPair<QByteArray, QByteArray> ScopeNamePair;
typedef QPair<QByteArray, int> NameIntPair;
typedef QSharedPointer<TypeStreamer> TypeStreamerPointer;
typedef QVector<PropertyReader> PropertyReaderVector;
typedef QVector<PropertyWriter> PropertyWriterVector;
typedef QPair<QVariant, QVariant> QVariantPair;
typedef QList<QVariantPair> QVariantPairList;
Q_DECLARE_METATYPE(QVariantPairList)
/// Streams integer identifiers that conform to the following pattern: each ID encountered in the stream is either one that
/// has been sent (received) before, or is one more than the highest previously encountered ID (starting at zero). This allows
/// us to use the minimum number of bits to encode the IDs.
@ -856,6 +862,8 @@ public:
virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const;
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual bool equal(const QVariant& first, const QVariant& second) const;
virtual void write(Bitstream& out, const QVariant& value) const;
@ -929,6 +937,7 @@ public:
EnumTypeStreamer(const QMetaEnum& metaEnum);
virtual const char* getName() const;
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual Category getCategory() const;
virtual int getBits() const;
virtual QMetaEnum getMetaEnum() const;
@ -966,6 +975,36 @@ private:
QHash<int, int> _mappings;
};
/// Base class for generic type streamers, which contain all the metadata required to write out a type.
class GenericTypeStreamer : public TypeStreamer {
public:
GenericTypeStreamer(const QByteArray& name);
virtual const char* getName() const;
private:
QByteArray _name;
};
/// A streamer for generic enums.
class GenericEnumTypeStreamer : public GenericTypeStreamer {
public:
GenericEnumTypeStreamer(const QByteArray& name, const QVector<NameIntPair>& values, int bits, const QByteArray& hash);
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual void write(Bitstream& out, const QVariant& value) const;
virtual Category getCategory() const;
private:
QVector<NameIntPair> _values;
int _bits;
QByteArray _hash;
};
/// Contains a value along with a pointer to its streamer.
class GenericValue {
public:
@ -986,7 +1025,7 @@ private:
Q_DECLARE_METATYPE(GenericValue)
/// A streamer class for generic values.
class GenericTypeStreamer : public SimpleTypeStreamer<GenericValue> {
class GenericValueStreamer : public SimpleTypeStreamer<GenericValue> {
public:
virtual const TypeStreamer* getStreamerToWrite(const QVariant& value) const;
@ -1022,6 +1061,24 @@ private:
QVector<StreamerIndexPair> _fields;
};
typedef QPair<TypeStreamerPointer, QByteArray> StreamerNamePair;
/// A streamer for generic enums.
class GenericStreamableTypeStreamer : public GenericTypeStreamer {
public:
GenericStreamableTypeStreamer(const QByteArray& name, const QVector<StreamerNamePair>& fields, const QByteArray& hash);
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual void write(Bitstream& out, const QVariant& value) const;
virtual Category getCategory() const;
private:
QVector<StreamerNamePair> _fields;
QByteArray _hash;
};
/// Base template for collection streamers.
template<class T> class CollectionTypeStreamer : public SimpleTypeStreamer<T> {
};
@ -1030,6 +1087,7 @@ template<class T> class CollectionTypeStreamer : public SimpleTypeStreamer<T> {
template<class T> class CollectionTypeStreamer<QList<T> > : public SimpleTypeStreamer<QList<T> > {
public:
virtual void writeMetadata(Bitstream& out, bool full) const { out << getValueStreamer(); }
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
virtual void insert(QVariant& object, const QVariant& value) const {
@ -1046,6 +1104,7 @@ public:
template<class T> class CollectionTypeStreamer<QVector<T> > : public SimpleTypeStreamer<QVector<T> > {
public:
virtual void writeMetadata(Bitstream& out, bool full) const { out << getValueStreamer(); }
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::LIST_CATEGORY; }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
virtual void insert(QVariant& object, const QVariant& value) const {
@ -1073,10 +1132,26 @@ protected:
TypeStreamerPointer _valueStreamer;
};
/// A streamer for generic lists.
class GenericListTypeStreamer : public GenericTypeStreamer {
public:
GenericListTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer);
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual void write(Bitstream& out, const QVariant& value) const;
virtual Category getCategory() const;
private:
TypeStreamerPointer _valueStreamer;
};
/// A streamer for set types.
template<class T> class CollectionTypeStreamer<QSet<T> > : public SimpleTypeStreamer<QSet<T> > {
public:
virtual void writeMetadata(Bitstream& out, bool full) const { out << getValueStreamer(); }
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::SET_CATEGORY; }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<T>()); }
virtual void insert(QVariant& object, const QVariant& value) const {
@ -1094,10 +1169,20 @@ public:
virtual void readRawDelta(Bitstream& in, QVariant& object, const QVariant& reference) const;
};
/// A streamer for generic sets.
class GenericSetTypeStreamer : public GenericListTypeStreamer {
public:
GenericSetTypeStreamer(const QByteArray& name, const TypeStreamerPointer& valueStreamer);
virtual Category getCategory() const;
};
/// A streamer for hash types.
template<class K, class V> class CollectionTypeStreamer<QHash<K, V> > : public SimpleTypeStreamer<QHash<K, V> > {
public:
virtual void writeMetadata(Bitstream& out, bool full) const { out << getKeyStreamer() << getValueStreamer(); }
virtual TypeStreamer::Category getCategory() const { return TypeStreamer::MAP_CATEGORY; }
virtual const TypeStreamer* getKeyStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<K>()); }
virtual const TypeStreamer* getValueStreamer() const { return Bitstream::getTypeStreamer(qMetaTypeId<V>()); }
@ -1126,6 +1211,23 @@ private:
TypeStreamerPointer _valueStreamer;
};
/// A streamer for generic maps.
class GenericMapTypeStreamer : public GenericTypeStreamer {
public:
GenericMapTypeStreamer(const QByteArray& name, const TypeStreamerPointer& keyStreamer,
const TypeStreamerPointer& valueStreamer);
virtual void writeMetadata(Bitstream& out, bool full) const;
virtual void write(Bitstream& out, const QVariant& value) const;
virtual Category getCategory() const;
private:
TypeStreamerPointer _keyStreamer;
TypeStreamerPointer _valueStreamer;
};
/// Macro for registering simple type streamers.
#define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \
Bitstream::registerTypeStreamer(qMetaTypeId<X>(), new SimpleTypeStreamer<X>());