More enum stuff, with tests.

This commit is contained in:
Andrzej Kapolka 2014-06-04 17:24:43 -07:00
parent a4aa5eb4e8
commit 54a5bc3a49
4 changed files with 250 additions and 55 deletions

View file

@ -71,6 +71,10 @@ IDStreamer& IDStreamer::operator>>(int& value) {
return *this;
}
static QByteArray getEnumName(const QMetaEnum& metaEnum) {
return QByteArray(metaEnum.scope()) + "::" + metaEnum.name();
}
int Bitstream::registerMetaObject(const char* className, const QMetaObject* metaObject) {
getMetaObjects().insert(className, metaObject);
@ -84,12 +88,7 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta
QMetaEnum metaEnum = metaObject->enumerator(i);
const TypeStreamer*& streamer = getEnumStreamers()[QPair<QByteArray, QByteArray>(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)));
getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum));
}
}
@ -135,6 +134,14 @@ void Bitstream::addTypeSubstitution(const QByteArray& typeName, int type) {
_typeStreamerSubstitutions.insert(typeName, getTypeStreamers().value(type));
}
void Bitstream::addTypeSubstitution(const QByteArray& typeName, const char* replacementTypeName) {
const TypeStreamer* streamer = getTypeStreamers().value(QMetaType::type(replacementTypeName));
if (!streamer) {
streamer = getEnumStreamersByName().value(replacementTypeName);
}
_typeStreamerSubstitutions.insert(typeName, streamer);
}
const int LAST_BIT_POSITION = BITS_IN_BYTE - 1;
Bitstream& Bitstream::write(const void* data, int bits, int offset) {
@ -659,9 +666,27 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
case TypeReader::SIMPLE_TYPE:
return *this;
case TypeReader::ENUM_TYPE:
return *this << streamer->getBits();
case TypeReader::ENUM_TYPE: {
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 TypeReader::LIST_TYPE:
case TypeReader::SET_TYPE:
return *this << streamer->getValueStreamer();
@ -694,6 +719,10 @@ Bitstream& Bitstream::operator<(const TypeStreamer* streamer) {
return *this;
}
static int getBitsForHighestValue(int highestValue) {
return (highestValue == 0) ? 0 : 1 + (int)(log(highestValue) / log(2.0));
}
Bitstream& Bitstream::operator>(TypeReader& reader) {
QByteArray typeName;
*this >> typeName;
@ -703,14 +732,9 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
}
const TypeStreamer* streamer = _typeStreamerSubstitutions.value(typeName);
if (!streamer) {
int index = typeName.indexOf("::");
if (index == -1) {
streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
} else {
int postIndex = index + 2;
streamer = getEnumStreamers().value(QPair<QByteArray, QByteArray>(
QByteArray::fromRawData(typeName.constData(), index),
QByteArray::fromRawData(typeName.constData() + postIndex, typeName.size() - postIndex)));
streamer = getTypeStreamers().value(QMetaType::type(typeName.constData()));
if (!streamer) {
streamer = getEnumStreamersByName().value(typeName);
}
}
if (!streamer) {
@ -728,12 +752,50 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
return *this;
case TypeReader::ENUM_TYPE: {
int bits;
*this >> bits;
if (streamer && streamer->getReaderType() == type) {
reader = TypeReader(typeName, streamer);
if (_metadataType == FULL_METADATA) {
int keyCount;
*this >> keyCount;
QMetaEnum metaEnum = (streamer && streamer->getReaderType() == TypeReader::ENUM_TYPE) ?
streamer->getMetaEnum() : QMetaEnum();
QHash<int, int> mappings;
bool matches = (keyCount == metaEnum.keyCount());
int highestValue = 0;
for (int i = 0; i < keyCount; i++) {
QByteArray key;
int value;
*this >> key >> value;
highestValue = qMax(value, highestValue);
int localValue = metaEnum.keyToValue(key);
if (localValue != -1) {
mappings.insert(value, localValue);
}
matches &= (value == localValue);
}
if (matches) {
reader = TypeReader(typeName, streamer);
} else {
reader = TypeReader(typeName, streamer, getBitsForHighestValue(highestValue), mappings);
}
} else {
reader = TypeReader(typeName, streamer, false, TypeReader::ENUM_TYPE, bits);
int bits;
*this >> bits;
QCryptographicHash hash(QCryptographicHash::Md5);
if (streamer && streamer->getReaderType() == TypeReader::ENUM_TYPE) {
QMetaEnum metaEnum = streamer->getMetaEnum();
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 localHashResult = hash.result();
QByteArray remoteHashResult(localHashResult.size(), 0);
read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE);
if (localHashResult == remoteHashResult) {
reader = TypeReader(typeName, streamer);
} else {
reader = TypeReader(typeName, streamer, bits, QHash<int, int>());
}
}
return *this;
}
@ -745,7 +807,7 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
valueReader.matchesExactly(streamer->getValueStreamer())) {
reader = TypeReader(typeName, streamer);
} else {
reader = TypeReader(typeName, streamer, false, (TypeReader::Type)type, 0, TypeReaderPointer(),
reader = TypeReader(typeName, streamer, (TypeReader::Type)type,
TypeReaderPointer(new TypeReader(valueReader)));
}
return *this;
@ -758,8 +820,8 @@ Bitstream& Bitstream::operator>(TypeReader& reader) {
valueReader.matchesExactly(streamer->getValueStreamer())) {
reader = TypeReader(typeName, streamer);
} else {
reader = TypeReader(typeName, streamer, false, TypeReader::MAP_TYPE, 0,
TypeReaderPointer(new TypeReader(keyReader)), TypeReaderPointer(new TypeReader(valueReader)));
reader = TypeReader(typeName, streamer, TypeReaderPointer(new TypeReader(keyReader)),
TypeReaderPointer(new TypeReader(valueReader)));
}
return *this;
}
@ -817,23 +879,20 @@ 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, TypeReader::STREAMABLE_TYPE,
0, TypeReaderPointer(), TypeReaderPointer(), fields);
reader = TypeReader(typeName, streamer, 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, TypeReader::STREAMABLE_TYPE,
0, TypeReaderPointer(), TypeReaderPointer(), fields);
reader = TypeReader(typeName, streamer, fields);
return *this;
}
}
reader = TypeReader(typeName, streamer);
return *this;
}
reader = TypeReader(typeName, streamer, false, TypeReader::STREAMABLE_TYPE,
0, TypeReaderPointer(), TypeReaderPointer(), fields);
reader = TypeReader(typeName, streamer, fields);
return *this;
}
@ -969,6 +1028,11 @@ QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& Bitstream::getEnumStr
return enumStreamers;
}
QHash<QByteArray, const TypeStreamer*>& Bitstream::getEnumStreamersByName() {
static QHash<QByteArray, const TypeStreamer*> enumStreamersByName;
return enumStreamersByName;
}
QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObject) {
QVector<PropertyReader> propertyReaders;
if (!metaObject) {
@ -995,24 +1059,62 @@ QVector<PropertyReader> Bitstream::getPropertyReaders(const QMetaObject* metaObj
return propertyReaders;
}
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, bool exactMatch, Type type, int bits,
const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader, const QVector<FieldReader>& fields) :
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) :
_typeName(typeName),
_streamer(streamer),
_exactMatch(exactMatch),
_type(type),
_exactMatch(true) {
}
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, int bits, const QHash<int, int>& mappings) :
_typeName(typeName),
_streamer(streamer),
_exactMatch(false),
_type(ENUM_TYPE),
_bits(bits),
_keyReader(keyReader),
_valueReader(valueReader),
_mappings(mappings) {
}
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, const QVector<FieldReader>& fields) :
_typeName(typeName),
_streamer(streamer),
_exactMatch(false),
_type(STREAMABLE_TYPE),
_fields(fields) {
}
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer,
Type type, const TypeReaderPointer& valueReader) :
_typeName(typeName),
_streamer(streamer),
_exactMatch(false),
_type(type),
_valueReader(valueReader) {
}
TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer,
const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader) :
_typeName(typeName),
_streamer(streamer),
_exactMatch(false),
_type(MAP_TYPE),
_keyReader(keyReader),
_valueReader(valueReader) {
}
QVariant TypeReader::read(Bitstream& in) const {
if (_exactMatch) {
return _streamer->read(in);
}
QVariant object = _streamer ? QVariant(_streamer->getType(), 0) : QVariant();
switch (_type) {
case ENUM_TYPE: {
int value = 0;
in.read(&value, _bits);
if (_streamer) {
_streamer->setEnumValue(object, value, _mappings);
}
break;
}
case STREAMABLE_TYPE: {
foreach (const FieldReader& field, _fields) {
field.read(in, _streamer, object);
@ -1069,6 +1171,14 @@ void TypeReader::readRawDelta(Bitstream& in, QVariant& object, const QVariant& r
return;
}
switch (_type) {
case ENUM_TYPE: {
int value = 0;
in.read(&value, _bits);
if (_streamer) {
_streamer->setEnumValue(object, value, _mappings);
}
break;
}
case STREAMABLE_TYPE: {
foreach (const FieldReader& field, _fields) {
field.readDelta(in, _streamer, object, reference);
@ -1269,6 +1379,10 @@ const char* TypeStreamer::getName() const {
return QMetaType::typeName(_type);
}
void TypeStreamer::setEnumValue(QVariant& object, int value, const QHash<int, int>& mappings) const {
// nothing by default
}
const QVector<MetaField>& TypeStreamer::getMetaFields() const {
static QVector<MetaField> emptyMetaFields;
return emptyMetaFields;
@ -1294,6 +1408,10 @@ int TypeStreamer::getBits() const {
return 0;
}
QMetaEnum TypeStreamer::getMetaEnum() const {
return QMetaEnum();
}
const TypeStreamer* TypeStreamer::getKeyStreamer() const {
return NULL;
}
@ -1338,9 +1456,17 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) {
return debug << (metaObject ? metaObject->className() : "null");
}
EnumTypeStreamer::EnumTypeStreamer(const QByteArray& name, int bits) :
_name(name),
_bits(bits) {
EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) :
_metaEnum(metaEnum),
_name(getEnumName(metaEnum)) {
setType(QMetaType::Int);
int highestValue = 0;
for (int j = 0; j < metaEnum.keyCount(); j++) {
highestValue = qMax(highestValue, metaEnum.value(j));
}
_bits = getBitsForHighestValue(highestValue);
}
const char* EnumTypeStreamer::getName() const {
@ -1355,6 +1481,10 @@ int EnumTypeStreamer::getBits() const {
return _bits;
}
QMetaEnum EnumTypeStreamer::getMetaEnum() const {
return _metaEnum;
}
bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) const {
return first.toInt() == second.toInt();
}
@ -1403,3 +1533,18 @@ void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVaria
value = intValue;
}
void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash<int, int>& mappings) const {
if (_metaEnum.isFlag()) {
int combined = 0;
for (QHash<int, int>::const_iterator it = mappings.constBegin(); it != mappings.constEnd(); it++) {
if (value & it.key()) {
combined |= it.value();
}
}
object = combined;
} else {
object = mappings.value(value);
}
}

View file

@ -236,6 +236,9 @@ public:
/// Substitutes the supplied type for the given type name's default mapping.
void addTypeSubstitution(const QByteArray& typeName, int type);
/// Substitutes the named type for the given type name's default mapping.
void addTypeSubstitution(const QByteArray& typeName, const char* replacementTypeName);
/// Writes a set of bits to the underlying stream.
/// \param bits the number of bits to write
/// \param offset the offset of the first bit
@ -424,6 +427,7 @@ private:
static QMultiHash<const QMetaObject*, const QMetaObject*>& getMetaObjectSubClasses();
static QHash<int, const TypeStreamer*>& getTypeStreamers();
static QHash<QPair<QByteArray, QByteArray>, const TypeStreamer*>& getEnumStreamers();
static QHash<QByteArray, const TypeStreamer*>& getEnumStreamersByName();
static QVector<PropertyReader> getPropertyReaders(const QMetaObject* metaObject);
};
@ -716,11 +720,18 @@ public:
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, int bits = 0, const TypeReaderPointer& keyReader = TypeReaderPointer(),
const TypeReaderPointer& valueReader = TypeReaderPointer(),
const QVector<FieldReader>& fields = QVector<FieldReader>());
TypeReader(const QByteArray& typeName = QByteArray(), const TypeStreamer* streamer = NULL);
TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, int bits, const QHash<int, int>& mappings);
TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, const QVector<FieldReader>& fields);
TypeReader(const QByteArray& typeName, const TypeStreamer* streamer, Type type,
const TypeReaderPointer& valueReader);
TypeReader(const QByteArray& typeName, const TypeStreamer* streamer,
const TypeReaderPointer& keyReader, const TypeReaderPointer& valueReader);
const QByteArray& getTypeName() const { return _typeName; }
const TypeStreamer* getStreamer() const { return _streamer; }
@ -740,6 +751,7 @@ private:
bool _exactMatch;
Type _type;
int _bits;
QHash<int, int> _mappings;
TypeReaderPointer _keyReader;
TypeReaderPointer _valueReader;
QVector<FieldReader> _fields;
@ -871,6 +883,8 @@ public:
virtual void writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const = 0;
virtual void readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const = 0;
virtual void setEnumValue(QVariant& object, int value, const QHash<int, int>& mappings) const;
virtual const QVector<MetaField>& getMetaFields() const;
virtual int getFieldIndex(const QByteArray& name) const;
virtual void setField(QVariant& object, int index, const QVariant& value) const;
@ -879,6 +893,7 @@ public:
virtual TypeReader::Type getReaderType() const;
virtual int getBits() const;
virtual QMetaEnum getMetaEnum() const;
virtual const TypeStreamer* getKeyStreamer() const;
virtual const TypeStreamer* getValueStreamer() const;
@ -923,11 +938,12 @@ public:
class EnumTypeStreamer : public TypeStreamer {
public:
EnumTypeStreamer(const QByteArray& name, int bits);
EnumTypeStreamer(const QMetaEnum& metaEnum);
virtual const char* getName() const;
virtual TypeReader::Type getReaderType() const;
virtual int getBits() const;
virtual QMetaEnum getMetaEnum() 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;
@ -935,9 +951,11 @@ public:
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;
virtual void setEnumValue(QVariant& object, int value, const QHash<int, int>& mappings) const;
private:
QMetaEnum _metaEnum;
QByteArray _name;
int _bits;
};

View file

@ -87,9 +87,11 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
QByteArray array;
QDataStream outStream(&array, QIODevice::WriteOnly);
Bitstream out(outStream, metadataType);
SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat(), getRandomTestEnum(), getRandomTestFlags());
SharedObjectPointer testObjectWrittenA = new TestSharedObjectA(randFloat(), TestSharedObjectA::SECOND_TEST_ENUM,
TestSharedObjectA::TestFlags(TestSharedObjectA::FIRST_TEST_FLAG | TestSharedObjectA::THIRD_TEST_FLAG));
out << testObjectWrittenA;
SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes());
SharedObjectPointer testObjectWrittenB = new TestSharedObjectB(randFloat(), createRandomBytes(),
TestSharedObjectB::THIRD_TEST_ENUM, TestSharedObjectB::SECOND_TEST_FLAG);
out << testObjectWrittenB;
TestMessageC messageWritten = createRandomMessageC();
out << QVariant::fromValue(messageWritten);
@ -102,6 +104,10 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
in.addMetaObjectSubstitution("TestSharedObjectA", &TestSharedObjectB::staticMetaObject);
in.addMetaObjectSubstitution("TestSharedObjectB", &TestSharedObjectA::staticMetaObject);
in.addTypeSubstitution("TestMessageC", TestMessageA::Type);
in.addTypeSubstitution("TestSharedObjectA::TestEnum", "TestSharedObjectB::TestEnum");
in.addTypeSubstitution("TestSharedObjectB::TestEnum", "TestSharedObjectA::TestEnum");
in.addTypeSubstitution("TestSharedObjectA::TestFlags", "TestSharedObjectB::TestFlags");
in.addTypeSubstitution("TestSharedObjectB::TestFlags", "TestSharedObjectA::TestFlags");
SharedObjectPointer testObjectReadA;
in >> testObjectReadA;
@ -109,8 +115,11 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
qDebug() << "Wrong class for A" << testObjectReadA << metadataType;
return true;
}
if (metadataType == Bitstream::FULL_METADATA && static_cast<TestSharedObjectA*>(testObjectWrittenA.data())->getFoo() !=
static_cast<TestSharedObjectB*>(testObjectReadA.data())->getFoo()) {
if (metadataType == Bitstream::FULL_METADATA && (static_cast<TestSharedObjectA*>(testObjectWrittenA.data())->getFoo() !=
static_cast<TestSharedObjectB*>(testObjectReadA.data())->getFoo() ||
static_cast<TestSharedObjectB*>(testObjectReadA.data())->getBaz() != TestSharedObjectB::SECOND_TEST_ENUM ||
static_cast<TestSharedObjectB*>(testObjectReadA.data())->getBong() !=
TestSharedObjectB::TestFlags(TestSharedObjectB::FIRST_TEST_FLAG | TestSharedObjectB::THIRD_TEST_FLAG))) {
QDebug debug = qDebug() << "Failed to transfer shared field from A to B";
testObjectWrittenA->dump(debug);
testObjectReadA->dump(debug);
@ -123,8 +132,10 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
qDebug() << "Wrong class for B" << testObjectReadB << metadataType;
return true;
}
if (metadataType == Bitstream::FULL_METADATA && static_cast<TestSharedObjectB*>(testObjectWrittenB.data())->getFoo() !=
static_cast<TestSharedObjectA*>(testObjectReadB.data())->getFoo()) {
if (metadataType == Bitstream::FULL_METADATA && (static_cast<TestSharedObjectB*>(testObjectWrittenB.data())->getFoo() !=
static_cast<TestSharedObjectA*>(testObjectReadB.data())->getFoo() ||
static_cast<TestSharedObjectA*>(testObjectReadB.data())->getBaz() != TestSharedObjectA::THIRD_TEST_ENUM ||
static_cast<TestSharedObjectA*>(testObjectReadB.data())->getBong() != TestSharedObjectA::SECOND_TEST_FLAG)) {
QDebug debug = qDebug() << "Failed to transfer shared field from B to A";
testObjectWrittenB->dump(debug);
testObjectReadB->dump(debug);
@ -433,9 +444,11 @@ void TestSharedObjectA::setFoo(float foo) {
}
}
TestSharedObjectB::TestSharedObjectB(float foo, const QByteArray& bar) :
TestSharedObjectB::TestSharedObjectB(float foo, const QByteArray& bar, TestEnum baz, TestFlags bong) :
_foo(foo),
_bar(bar) {
_bar(bar),
_baz(baz),
_bong(bong) {
sharedObjectsCreated++;
}

View file

@ -109,12 +109,23 @@ private:
/// Another simple shared object.
class TestSharedObjectB : public SharedObject {
Q_OBJECT
Q_ENUMS(TestEnum)
Q_FLAGS(TestFlag TestFlags)
Q_PROPERTY(float foo READ getFoo WRITE setFoo)
Q_PROPERTY(QByteArray bar READ getBar WRITE setBar)
Q_PROPERTY(TestEnum baz READ getBaz WRITE setBaz)
Q_PROPERTY(TestFlags bong READ getBong WRITE setBong)
public:
Q_INVOKABLE TestSharedObjectB(float foo = 0.0f, const QByteArray& bar = QByteArray());
enum TestEnum { ZEROTH_TEST_ENUM, FIRST_TEST_ENUM, SECOND_TEST_ENUM, THIRD_TEST_ENUM, FOURTH_TEST_ENUM };
enum TestFlag { NO_TEST_FLAGS = 0x0, ZEROTH_TEST_FLAG = 0x01, FIRST_TEST_FLAG = 0x02,
SECOND_TEST_FLAG = 0x04, THIRD_TEST_FLAG = 0x08, FOURTH_TEST_FLAG = 0x10 };
Q_DECLARE_FLAGS(TestFlags, TestFlag)
Q_INVOKABLE TestSharedObjectB(float foo = 0.0f, const QByteArray& bar = QByteArray(),
TestEnum baz = FIRST_TEST_ENUM, TestFlags bong = 0);
virtual ~TestSharedObjectB();
void setFoo(float foo) { _foo = foo; }
@ -123,10 +134,18 @@ public:
void setBar(const QByteArray& bar) { _bar = bar; }
const QByteArray& getBar() const { return _bar; }
void setBaz(TestEnum baz) { _baz = baz; }
TestEnum getBaz() const { return _baz; }
void setBong(TestFlags bong) { _bong = bong; }
TestFlags getBong() const { return _bong; }
private:
float _foo;
QByteArray _bar;
TestEnum _baz;
TestFlags _bong;
};
/// A simple test message.