From 90e2145fc4d3bed08ea824a6857926b359cb3339 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 3 Jun 2014 17:17:02 -0700 Subject: [PATCH] Working on enum streaming. --- libraries/metavoxels/src/Bitstream.cpp | 230 ++++++++++++++++++------- libraries/metavoxels/src/Bitstream.h | 40 ++++- tests/metavoxels/src/MetavoxelTests.h | 2 +- 3 files changed, 208 insertions(+), 64 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index f3ba1cca4d..5ce04b272a 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -78,6 +78,21 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta for (const QMetaObject* superClass = metaObject; superClass; superClass = superClass->superClass()) { getMetaObjectSubClasses().insert(superClass, metaObject); } + + // register the streamers for all enumerators + for (int i = 0; i < metaObject->enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject->enumerator(i); + const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; + if (!streamer) { + int highestValue = 0; + for (int j = 0; j < metaEnum.keyCount(); j++) { + highestValue = qMax(highestValue, metaEnum.value(j)); + } + streamer = new EnumTypeStreamer(QByteArray(metaEnum.scope()) + "::" + metaEnum.name(), + highestValue == 0 ? 0 : 1 + (int)(log(highestValue) / log(2.0))); + } + } + return 0; } @@ -280,16 +295,8 @@ void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) { } const QMetaObject* metaObject = value->metaObject(); _metaObjectStreamer << metaObject; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored(value)) { - continue; - } - const TypeStreamer* streamer = getTypeStreamers().value(property.userType()); - if (streamer) { - streamer->writeDelta(*this, property.read(value), reference && metaObject == reference->metaObject() ? - property.read(reference) : QVariant()); - } + foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + propertyWriter.writeDelta(*this, value, reference); } } @@ -466,15 +473,8 @@ Bitstream& Bitstream::operator<<(const QObject* object) { } const QMetaObject* metaObject = object->metaObject(); _metaObjectStreamer << metaObject; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored(object)) { - continue; - } - const TypeStreamer* streamer = getTypeStreamers().value(property.userType()); - if (streamer) { - streamer->write(*this, property.read(object)); - } + foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + propertyWriter.write(*this, object); } return *this; } @@ -558,25 +558,12 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) { if (_metadataType == NO_METADATA) { return *this; } - int storedPropertyCount = 0; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (property.isStored() && getTypeStreamers().contains(property.userType())) { - storedPropertyCount++; - } - } - *this << storedPropertyCount; + const QVector& propertyWriters = getPropertyWriters(metaObject); + *this << propertyWriters.size(); QCryptographicHash hash(QCryptographicHash::Md5); - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; - } - const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType()); - if (!typeStreamer) { - continue; - } - _typeStreamerStreamer << typeStreamer; + foreach (const PropertyWriter& propertyWriter, propertyWriters) { + _typeStreamerStreamer << propertyWriter.getStreamer(); + const QMetaProperty& property = propertyWriter.getProperty(); if (_metadataType == FULL_METADATA) { *this << QByteArray::fromRawData(property.name(), strlen(property.name())); } else { @@ -629,25 +616,18 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; if (metaObject) { - int propertyIndex = 0; - for (int i = 0; i < metaObject->propertyCount(); i++) { - QMetaProperty property = metaObject->property(i); - if (!property.isStored()) { - continue; + const QVector& propertyWriters = getPropertyWriters(metaObject); + if (propertyWriters.size() == properties.size()) { + for (int i = 0; i < propertyWriters.size(); i++) { + const PropertyWriter& propertyWriter = propertyWriters.at(i); + if (!properties.at(i).getReader().matchesExactly(propertyWriter.getStreamer())) { + matches = false; + break; + } + const QMetaProperty& property = propertyWriter.getProperty(); + hash.addData(property.name(), strlen(property.name()) + 1); } - const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType()); - if (!typeStreamer) { - continue; - } - if (propertyIndex >= properties.size() || - !properties.at(propertyIndex).getReader().matchesExactly(typeStreamer)) { - matches = false; - break; - } - hash.addData(property.name(), strlen(property.name()) + 1); - propertyIndex++; - } - if (propertyIndex != properties.size()) { + } else { matches = false; } } @@ -668,7 +648,7 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { *this << QByteArray(); return *this; } - const char* typeName = QMetaType::typeName(streamer->getType()); + const char* typeName = streamer->getName(); *this << QByteArray::fromRawData(typeName, strlen(typeName)); if (_metadataType == NO_METADATA) { return *this; @@ -679,6 +659,9 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) { case TypeReader::SIMPLE_TYPE: return *this; + case TypeReader::ENUM_TYPE: + return *this << streamer->getBits(); + case TypeReader::LIST_TYPE: case TypeReader::SET_TYPE: return *this << streamer->getValueStreamer(); @@ -720,7 +703,15 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { } const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName); if (!streamer) { - streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + int index = typeName.indexOf("::"); + if (index == -1) { + streamer = getTypeStreamers().value(QMetaType::type(typeName.constData())); + } else { + int postIndex = index + 2; + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(typeName.constData(), index), + QByteArray::fromRawData(typeName.constData() + postIndex, typeName.size() - postIndex))); + } } if (!streamer) { qWarning() << "Unknown type name: " << typeName << "\n"; @@ -735,7 +726,13 @@ Bitstream& Bitstream::operator>(TypeReader& reader) { case TypeReader::SIMPLE_TYPE: reader = TypeReader(typeName, streamer); return *this; - + + case TypeReader::ENUM_TYPE: { + int bits; + *this >> bits; + reader = TypeReader(typeName, streamer); + return *this; + } case TypeReader::LIST_TYPE: case TypeReader::SET_TYPE: { TypeReader valueReader; @@ -923,6 +920,31 @@ void Bitstream::clearSharedObject(QObject* object) { } } +const QVector& Bitstream::getPropertyWriters(const QMetaObject* metaObject) { + QVector& propertyWriters = _propertyWriters[metaObject]; + if (propertyWriters.isEmpty()) { + for (int i = 0; i < metaObject->propertyCount(); i++) { + QMetaProperty property = metaObject->property(i); + if (!property.isStored()) { + continue; + } + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + propertyWriters.append(PropertyWriter(property, streamer)); + } + } + } + return propertyWriters; +} + QHash& Bitstream::getMetaObjects() { static QHash metaObjects; return metaObjects; @@ -938,6 +960,11 @@ QHash& Bitstream::getTypeStreamers() { return typeStreamers; } +QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { + static QHash, const TypeStreamer*> enumStreamers; + return enumStreamers; +} + QVector Bitstream::getPropertyReaders(const QMetaObject* metaObject) { QVector propertyReaders; if (!metaObject) { @@ -948,9 +975,17 @@ QVector Bitstream::getPropertyReaders(const QMetaObject* metaObj if (!property.isStored()) { continue; } - const TypeStreamer* typeStreamer = getTypeStreamers().value(property.userType()); - if (typeStreamer) { - propertyReaders.append(PropertyReader(TypeReader(QByteArray(), typeStreamer), property)); + const TypeStreamer* streamer; + if (property.isEnumType()) { + QMetaEnum metaEnum = property.enumerator(); + streamer = getEnumStreamers().value(QPair( + QByteArray::fromRawData(metaEnum.scope(), strlen(metaEnum.scope())), + QByteArray::fromRawData(metaEnum.name(), strlen(metaEnum.name())))); + } else { + streamer = getTypeStreamers().value(property.userType()); + } + if (streamer) { + propertyReaders.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); } } return propertyReaders; @@ -1225,6 +1260,10 @@ MetaField::MetaField(const QByteArray& name, const TypeStreamer* streamer) : TypeStreamer::~TypeStreamer() { } +const char* TypeStreamer::getName() const { + return QMetaType::typeName(_type); +} + const QVector& TypeStreamer::getMetaFields() const { static QVector emptyMetaFields; return emptyMetaFields; @@ -1246,6 +1285,10 @@ TypeReader::Type TypeStreamer::getReaderType() const { return TypeReader::SIMPLE_TYPE; } +int TypeStreamer::getBits() const { + return 0; +} + const TypeStreamer* TypeStreamer::getKeyStreamer() const { return NULL; } @@ -1290,3 +1333,68 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { return debug << (metaObject ? metaObject->className() : "null"); } +EnumTypeStreamer::EnumTypeStreamer(const QByteArray& name, int bits) : + _name(name), + _bits(bits) { +} + +const char* EnumTypeStreamer::getName() const { + return _name.constData(); +} + +TypeReader::Type EnumTypeStreamer::getReaderType() const { + return TypeReader::ENUM_TYPE; +} + +int EnumTypeStreamer::getBits() const { + return _bits; +} + +bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) const { + return first.toInt() == second.toInt(); +} + +void EnumTypeStreamer::write(Bitstream& out, const QVariant& value) const { + int intValue = value.toInt(); + out.write(&intValue, _bits); +} + +QVariant EnumTypeStreamer::read(Bitstream& in) const { + int intValue = 0; + in.read(&intValue, _bits); + return intValue; +} + +void EnumTypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + int intValue = value.toInt(), intReference = reference.toInt(); + if (intValue == intReference) { + out << false; + } else { + out << true; + out.write(&intValue, _bits); + } +} + +void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + bool changed; + in >> changed; + if (changed) { + int intValue = 0; + in.read(&intValue, _bits); + value = intValue; + } else { + value = reference; + } +} + +void EnumTypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + int intValue = value.toInt(); + out.write(&intValue, _bits); +} + +void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + int intValue = 0; + in.read(&intValue, _bits); + value = intValue; +} + diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 7e1551346a..3ea5eb7150 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -38,6 +38,7 @@ class FieldReader; class ObjectReader; class OwnedAttributeValue; class PropertyReader; +class PropertyWriter; class TypeReader; class TypeStreamer; @@ -396,6 +397,8 @@ private slots: private: + const QVector& getPropertyWriters(const QMetaObject* metaObject); + QDataStream& _underlying; quint8 _byte; int _position; @@ -415,9 +418,12 @@ private: QHash _metaObjectSubstitutions; QHash _typeStreamerSubstitutions; + QHash > _propertyWriters; + static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); + static QHash, const TypeStreamer*>& getEnumStreamers(); static QVector getPropertyReaders(const QMetaObject* metaObject); }; @@ -708,7 +714,7 @@ typedef QSharedPointer TypeReaderPointer; class TypeReader { public: - enum Type { SIMPLE_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; + enum Type { SIMPLE_TYPE, ENUM_TYPE, STREAMABLE_TYPE, LIST_TYPE, SET_TYPE, MAP_TYPE }; TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL, bool exactMatch = true, Type type = SIMPLE_TYPE, const TypeReaderPointer& keyReader = TypeReaderPointer(), @@ -804,12 +810,15 @@ private: QMetaProperty _property; }; -/// Contains the information necessary to obtain an object property and write it to the stream. +/// Contains the information required to obtain an object property and write it to the stream. class PropertyWriter { public: PropertyWriter(const QMetaProperty& property = QMetaProperty(), const TypeStreamer* streamer = NULL); + const QMetaProperty& getProperty() const { return _property; } + const TypeStreamer* getStreamer() const { return _streamer; } + void write(Bitstream& out, const QObject* object) const; void writeDelta(Bitstream& out, const QObject* object, const QObject* reference) const; @@ -848,6 +857,8 @@ public: void setType(int type) { _type = type; } int getType() const { return _type; } + virtual const char* getName() const; + virtual bool equal(const QVariant& first, const QVariant& second) const = 0; virtual void write(Bitstream& out, const QVariant& value) const = 0; @@ -866,6 +877,8 @@ public: virtual TypeReader::Type getReaderType() const; + virtual int getBits() const; + virtual const TypeStreamer* getKeyStreamer() const; virtual const TypeStreamer* getValueStreamer() const; @@ -905,6 +918,29 @@ public: T rawValue; in.readRawDelta(rawValue, reference.value()); value = QVariant::fromValue(rawValue); } }; +/// A streamer class for enumerated types. +class EnumTypeStreamer : public TypeStreamer { +public: + + EnumTypeStreamer(const QByteArray& name, int bits); + + virtual const char* getName() const; + virtual TypeReader::Type getReaderType() const; + virtual int getBits() const; + virtual bool equal(const QVariant& first, const QVariant& second) const; + virtual void write(Bitstream& out, const QVariant& value) const; + virtual QVariant read(Bitstream& in) const; + virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; + virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; + virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const; + virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const; + +private: + + QByteArray _name; + int _bits; +}; + /// A streamer for types compiled by mtc. template class StreamableTypeStreamer : public SimpleTypeStreamer { public: diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 6e0b857328..a4aa428a1e 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -80,7 +80,7 @@ public: enum TestEnum { FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM }; - enum TestFlag { NO_TEST_FLAGS = 0x0, FIRST_TEST_FLAG = 0x01, SECOND_TEST_FLAG = 0x02, THIRD_TEST_FLAG = 0x03 }; + enum TestFlag { NO_TEST_FLAGS = 0x0, FIRST_TEST_FLAG = 0x01, SECOND_TEST_FLAG = 0x02, THIRD_TEST_FLAG = 0x04 }; Q_DECLARE_FLAGS(TestFlags, TestFlag) Q_INVOKABLE TestSharedObjectA(float foo = 0.0f, TestEnum baz = FIRST_TEST_ENUM, TestFlags bong = 0);