From c44dba78cb3ad4458fe3abb75695967afb763c27 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 15:32:55 -0700 Subject: [PATCH 1/9] Provide a reasonably painless way to stream enums that aren't object properties. --- libraries/metavoxels/src/Bitstream.h | 34 ++++++++++++++++++++++--- tests/metavoxels/src/MetavoxelTests.cpp | 7 +++-- tests/metavoxels/src/MetavoxelTests.h | 3 +++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 146713910f..9945284775 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -1037,12 +1037,12 @@ public: }; /// Macro for registering simple type streamers. -#define REGISTER_SIMPLE_TYPE_STREAMER(x) static int x##Streamer = \ - Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); +#define REGISTER_SIMPLE_TYPE_STREAMER(X) static int X##Streamer = \ + Bitstream::registerTypeStreamer(qMetaTypeId(), new SimpleTypeStreamer()); /// Macro for registering collection type streamers. -#define REGISTER_COLLECTION_TYPE_STREAMER(x) static int x##Streamer = \ - Bitstream::registerTypeStreamer(qMetaTypeId(), new CollectionTypeStreamer()); +#define REGISTER_COLLECTION_TYPE_STREAMER(X) static int x##Streamer = \ + Bitstream::registerTypeStreamer(qMetaTypeId(), new CollectionTypeStreamer()); /// Declares the metatype and the streaming operators. The last lines /// ensure that the generated file will be included in the link phase. @@ -1077,6 +1077,25 @@ public: _Pragma(STRINGIFY(unused(_TypePtr##X))) #endif +#define DECLARE_ENUM_METATYPE(S, N) Q_DECLARE_METATYPE(S::N) \ + Bitstream& operator<<(Bitstream& out, const S::N& obj); \ + Bitstream& operator>>(Bitstream& in, S::N& obj); \ + template<> inline void Bitstream::writeRawDelta(const S::N& value, const S::N& reference) { *this << value; } \ + template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; } + +#define IMPLEMENT_ENUM_METATYPE(S, N) \ + static int S##N##MetaTypeId = registerEnumMetaType(S::staticMetaObject.enumerator( \ + S::staticMetaObject.indexOfEnumerator(#N))); \ + Bitstream& operator<<(Bitstream& out, const S::N& obj) { \ + static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ + return out.write(&obj, bits); \ + } \ + Bitstream& operator>>(Bitstream& in, S::N& obj) { \ + static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ + obj = (S::N)0; \ + return in.read(&obj, bits); \ + } + /// Registers a simple type and its streamer. template int registerSimpleMetaType() { int type = qRegisterMetaType(); @@ -1084,6 +1103,13 @@ template int registerSimpleMetaType() { return type; } +/// Registers an enum type and its streamer. +template int registerEnumMetaType(const QMetaEnum& metaEnum) { + int type = qRegisterMetaType(); + Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaEnum)); + return type; +} + /// Registers a streamable type and its streamer. template int registerStreamableMetaType() { int type = qRegisterMetaType(); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 603f63b587..cb1b5c7900 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -20,6 +20,8 @@ REGISTER_META_OBJECT(TestSharedObjectA) REGISTER_META_OBJECT(TestSharedObjectB) +IMPLEMENT_ENUM_METATYPE(TestSharedObjectA, TestEnum) + MetavoxelTests::MetavoxelTests(int& argc, char** argv) : QCoreApplication(argc, argv) { } @@ -80,6 +82,7 @@ static TestMessageC createRandomMessageC() { message.bar = rand(); message.baz = randFloat(); message.bong.foo = createRandomBytes(); + message.bong.baz = getRandomTestEnum(); return message; } @@ -252,7 +255,7 @@ static QVariant createRandomMessage() { return QVariant::fromValue(message); } case 1: { - TestMessageB message = { createRandomBytes(), createRandomSharedObject() }; + TestMessageB message = { createRandomBytes(), createRandomSharedObject(), getRandomTestEnum() }; return QVariant::fromValue(message); } case 2: @@ -273,7 +276,7 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe } else if (type == TestMessageB::Type) { TestMessageB first = firstMessage.value(); TestMessageB second = secondMessage.value(); - return first.foo == second.foo && equals(first.bar, second.bar); + return first.foo == second.foo && equals(first.bar, second.bar) && first.baz == second.baz; } else if (type == TestMessageC::Type) { return firstMessage.value() == secondMessage.value(); diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 5e020b1e60..ffd1311f00 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -106,6 +106,8 @@ private: TestFlags _bong; }; +DECLARE_ENUM_METATYPE(TestSharedObjectA, TestEnum) + /// Another simple shared object. class TestSharedObjectB : public SharedObject { Q_OBJECT @@ -169,6 +171,7 @@ public: STREAM QByteArray foo; STREAM SharedObjectPointer bar; + STREAM TestSharedObjectA::TestEnum baz; }; DECLARE_STREAMABLE_METATYPE(TestMessageB) From 887561a4e134e97d30ad11131c83952fc986815c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 15:39:43 -0700 Subject: [PATCH 2/9] Slight simplification. --- libraries/metavoxels/src/Bitstream.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 9945284775..caf0adf7fc 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -1084,19 +1084,18 @@ public: template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; } #define IMPLEMENT_ENUM_METATYPE(S, N) \ - static int S##N##MetaTypeId = registerEnumMetaType(S::staticMetaObject.enumerator( \ + static int S##N##Bits = registerEnumMetaType(S::staticMetaObject.enumerator( \ S::staticMetaObject.indexOfEnumerator(#N))); \ Bitstream& operator<<(Bitstream& out, const S::N& obj) { \ - static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ - return out.write(&obj, bits); \ + return out.write(&obj, S##N##Bits); \ } \ Bitstream& operator>>(Bitstream& in, S::N& obj) { \ - static int bits = static_cast(Bitstream::getTypeStreamer(qMetaTypeId()))->getBits(); \ obj = (S::N)0; \ - return in.read(&obj, bits); \ + return in.read(&obj, S##N##Bits); \ } /// Registers a simple type and its streamer. +/// \return the metatype id template int registerSimpleMetaType() { int type = qRegisterMetaType(); Bitstream::registerTypeStreamer(type, new SimpleTypeStreamer()); @@ -1104,13 +1103,16 @@ template int registerSimpleMetaType() { } /// Registers an enum type and its streamer. +/// \return the number of bits required to stream the enum template int registerEnumMetaType(const QMetaEnum& metaEnum) { int type = qRegisterMetaType(); - Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaEnum)); - return type; + EnumTypeStreamer* streamer = new EnumTypeStreamer(metaEnum); + Bitstream::registerTypeStreamer(type, streamer); + return streamer->getBits(); } /// Registers a streamable type and its streamer. +/// \return the metatype id template int registerStreamableMetaType() { int type = qRegisterMetaType(); Bitstream::registerTypeStreamer(type, new StreamableTypeStreamer()); @@ -1118,6 +1120,7 @@ template int registerStreamableMetaType() { } /// Registers a collection type and its streamer. +/// \return the metatype id template int registerCollectionMetaType() { int type = qRegisterMetaType(); Bitstream::registerTypeStreamer(type, new CollectionTypeStreamer()); From c333fb904f88fa109a8776bd5a8a11b8ed17bbd0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 16:45:13 -0700 Subject: [PATCH 3/9] Working on tests for delta streaming. --- tests/metavoxels/src/MetavoxelTests.cpp | 32 ++++++++++++++++++++++++- tests/metavoxels/src/MetavoxelTests.h | 21 ++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index cb1b5c7900..c4d973ad05 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -229,6 +229,20 @@ Endpoint::Endpoint(const QByteArray& datagramHeader) : connect(_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); + connect(_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int))); + connect(_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int))); + + // insert the baseline send record + SendRecord sendRecord = { 0 }; + _sendRecords.append(sendRecord); + + // insert the baseline receive record + ReceiveRecord receiveRecord = { 0 }; + _receiveRecords.append(receiveRecord); + + // create the object that represents out delta-encoded state + //_localState = new TestSharedObjectA(); + connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), SLOT(handleReliableMessage(const QVariant&))); @@ -326,7 +340,7 @@ bool Endpoint::simulate(int iterationNumber) { // send a packet try { Bitstream& out = _sequencer->startPacket(); - SequencedTestMessage message = { iterationNumber, createRandomMessage() }; + SequencedTestMessage message = { iterationNumber, createRandomMessage(), _localState }; _unreliableMessagesSent.append(message); unreliableMessagesSent++; out << message; @@ -337,6 +351,10 @@ bool Endpoint::simulate(int iterationNumber) { return true; } + // record the send + SendRecord record = { _sequencer->getOutgoingPacketNumber(), _localState }; + _sendRecords.append(record); + return false; } @@ -387,6 +405,10 @@ void Endpoint::readMessage(Bitstream& in) { SequencedTestMessage message; in >> message; + // record the receipt + ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), message.state }; + _receiveRecords.append(record); + for (QList::iterator it = _other->_unreliableMessagesSent.begin(); it != _other->_unreliableMessagesSent.end(); it++) { if (it->sequenceNumber == message.sequenceNumber) { @@ -430,6 +452,14 @@ void Endpoint::readReliableChannel() { streamedBytesReceived += bytes.size(); } +void Endpoint::clearSendRecordsBefore(int index) { + _sendRecords.erase(_sendRecords.begin(), _sendRecords.begin() + index + 1); +} + +void Endpoint::clearReceiveRecordsBefore(int index) { + _receiveRecords.erase(_receiveRecords.begin(), _receiveRecords.begin() + index + 1); +} + TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) : _foo(foo), _baz(baz), diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index ffd1311f00..dc294692af 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -54,9 +54,29 @@ private slots: void handleReliableMessage(const QVariant& message); void readReliableChannel(); + void clearSendRecordsBefore(int index); + void clearReceiveRecordsBefore(int index); + private: + class SendRecord { + public: + int packetNumber; + SharedObjectPointer localState; + }; + + class ReceiveRecord { + public: + int packetNumber; + SharedObjectPointer remoteState; + }; + DatagramSequencer* _sequencer; + QList _sendRecords; + QList _receiveRecords; + + SharedObjectPointer _localState; + Endpoint* _other; QList > _delayedDatagrams; float _highPriorityMessagesToSend; @@ -195,6 +215,7 @@ public: STREAM int sequenceNumber; STREAM QVariant submessage; + STREAM SharedObjectPointer state; }; DECLARE_STREAMABLE_METATYPE(SequencedTestMessage) From 005a314695545fd1c9d24a6161f4e6bff77c0928 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 5 Jun 2014 17:30:19 -0700 Subject: [PATCH 4/9] Reenable enum streamers here. --- libraries/metavoxels/src/Bitstream.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 387b41a839..30d34580d7 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -92,14 +92,13 @@ int Bitstream::registerMetaObject(const char* className, const QMetaObject* meta } // register the streamers for all enumerators - // temporarily disabled: crashes on Windows - //for (int i = 0; i < metaObject->enumeratorCount(); i++) { - // QMetaEnum metaEnum = metaObject->enumerator(i); - // const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; - // if (!streamer) { - // getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); - // } - //} + for (int i = 0; i < metaObject->enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject->enumerator(i); + const TypeStreamer*& streamer = getEnumStreamers()[QPair(metaEnum.scope(), metaEnum.name())]; + if (!streamer) { + getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); + } + } return 0; } From 0fc6354b6cb14b5391761252183a167fb9999b32 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 11:18:55 -0700 Subject: [PATCH 5/9] Fix for streaming the same object. --- libraries/metavoxels/src/Bitstream.cpp | 6 ++++-- tests/metavoxels/src/MetavoxelTests.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 30d34580d7..bc187d9f3d 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -224,7 +224,8 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { } connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); QPointer& reference = _sharedObjectReferences[it.key()->getOriginID()]; - if (reference) { + if (reference && reference != it.key()) { + // the object has been replaced by a successor, so we can forget about the original _sharedObjectStreamer.removePersistentID(reference); reference->disconnect(this); } @@ -258,7 +259,8 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { continue; } QPointer& reference = _sharedObjectReferences[it.value()->getRemoteOriginID()]; - if (reference) { + if (reference && reference != it.value()) { + // the object has been replaced by a successor, so we can forget about the original _sharedObjectStreamer.removePersistentValue(reference.data()); } reference = it.value(); diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index c4d973ad05..eec26ae411 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -183,7 +183,7 @@ bool MetavoxelTests::run() { bob.setOther(&alice); // perform a large number of simulation iterations - const int SIMULATION_ITERATIONS = 100000; + const int SIMULATION_ITERATIONS = 10000; for (int i = 0; i < SIMULATION_ITERATIONS; i++) { if (alice.simulate(i) || bob.simulate(i)) { return true; @@ -241,7 +241,7 @@ Endpoint::Endpoint(const QByteArray& datagramHeader) : _receiveRecords.append(receiveRecord); // create the object that represents out delta-encoded state - //_localState = new TestSharedObjectA(); + _localState = new TestSharedObjectA(); connect(_sequencer->getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), SLOT(handleReliableMessage(const QVariant&))); From 56d9bc5215a60b72cc6696e9d21eb14f4caf312d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 11:37:45 -0700 Subject: [PATCH 6/9] Working on delta-streaming tests. --- tests/metavoxels/src/MetavoxelTests.cpp | 33 ++++++++++++++++++++++++- tests/metavoxels/src/MetavoxelTests.h | 1 + 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index eec26ae411..b2dcc1dd45 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -38,6 +38,7 @@ static int streamedBytesSent = 0; static int streamedBytesReceived = 0; static int sharedObjectsCreated = 0; static int sharedObjectsDestroyed = 0; +static int objectMutationsPerformed = 0; static QByteArray createRandomBytes(int minimumSize, int maximumSize) { QByteArray bytes(randIntInRange(minimumSize, maximumSize), 0); @@ -196,6 +197,7 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; + qDebug() << "Performed" << objectMutationsPerformed << "object mutations"; qDebug(); qDebug() << "Running serialization tests..."; @@ -272,13 +274,37 @@ static QVariant createRandomMessage() { TestMessageB message = { createRandomBytes(), createRandomSharedObject(), getRandomTestEnum() }; return QVariant::fromValue(message); } - case 2: default: { return QVariant::fromValue(createRandomMessageC()); } } } +static SharedObjectPointer mutate(const SharedObjectPointer& state) { + switch(randIntInRange(0, 3)) { + case 0: { + SharedObjectPointer newState = state->clone(true); + static_cast(newState.data())->setFoo(randFloat()); + objectMutationsPerformed++; + return newState; + } + case 1: { + SharedObjectPointer newState = state->clone(true); + static_cast(newState.data())->setBaz(getRandomTestEnum()); + objectMutationsPerformed++; + return newState; + } + case 2: { + SharedObjectPointer newState = state->clone(true); + static_cast(newState.data())->setBong(getRandomTestFlags()); + objectMutationsPerformed++; + return newState; + } + default: + return state; + } +} + static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMessage) { int type = firstMessage.userType(); if (secondMessage.userType() != type) { @@ -337,6 +363,9 @@ bool Endpoint::simulate(int iterationNumber) { _reliableMessagesToSend -= 1.0f; } + // tweak the local state + _localState = mutate(_localState); + // send a packet try { Bitstream& out = _sequencer->startPacket(); @@ -405,6 +434,8 @@ void Endpoint::readMessage(Bitstream& in) { SequencedTestMessage message; in >> message; + _remoteState = message.state; + // record the receipt ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), message.state }; _receiveRecords.append(record); diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index dc294692af..345ea624df 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -76,6 +76,7 @@ private: QList _receiveRecords; SharedObjectPointer _localState; + SharedObjectPointer _remoteState; Endpoint* _other; QList > _delayedDatagrams; From 361461516c8675897adb331edab325db298ebf1a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 14:26:20 -0700 Subject: [PATCH 7/9] Check the delta-encoded objects, report bytes sent/received. --- tests/metavoxels/src/MetavoxelTests.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index b2dcc1dd45..81f1840342 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -28,6 +28,8 @@ MetavoxelTests::MetavoxelTests(int& argc, char** argv) : static int datagramsSent = 0; static int datagramsReceived = 0; +static int bytesSent = 0; +static int bytesReceived = 0; static int highPriorityMessagesSent = 0; static int highPriorityMessagesReceived = 0; static int unreliableMessagesSent = 0; @@ -195,7 +197,8 @@ bool MetavoxelTests::run() { qDebug() << "Sent" << unreliableMessagesSent << "unreliable messages, received" << unreliableMessagesReceived; qDebug() << "Sent" << reliableMessagesSent << "reliable messages, received" << reliableMessagesReceived; qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; - qDebug() << "Sent" << datagramsSent << "datagrams, received" << datagramsReceived; + qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" << + datagramsReceived << "with" << bytesReceived << "bytes"; qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; qDebug() << "Performed" << objectMutationsPerformed << "object mutations"; qDebug(); @@ -389,6 +392,7 @@ bool Endpoint::simulate(int iterationNumber) { void Endpoint::sendDatagram(const QByteArray& datagram) { datagramsSent++; + bytesSent += datagram.size(); // some datagrams are dropped const float DROP_PROBABILITY = 0.1f; @@ -414,6 +418,7 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { _other->_sequencer->receivedDatagram(datagram); datagramsReceived++; + bytesReceived += datagram.size(); } void Endpoint::handleHighPriorityMessage(const QVariant& message) { @@ -446,6 +451,9 @@ void Endpoint::readMessage(Bitstream& in) { if (!messagesEqual(it->submessage, message.submessage)) { throw QString("Sent/received unreliable message mismatch."); } + if (!it->state->equals(message.state)) { + throw QString("Delta-encoded object mismatch."); + } _other->_unreliableMessagesSent.erase(_other->_unreliableMessagesSent.begin(), it + 1); unreliableMessagesReceived++; return; From 2fec0a9db603e09e7314a4221e761141a57b127d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 15:50:28 -0700 Subject: [PATCH 8/9] Fixes for Windows. --- libraries/metavoxels/src/Bitstream.cpp | 87 ++++++++++++++++---------- libraries/metavoxels/src/Bitstream.h | 27 ++++---- 2 files changed, 71 insertions(+), 43 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index bc187d9f3d..6f4af8ed5f 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -79,10 +79,6 @@ 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); @@ -90,16 +86,6 @@ 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) { - getEnumStreamersByName().insert(getEnumName(metaEnum), streamer = new EnumTypeStreamer(metaEnum)); - } - } - return 0; } @@ -1030,12 +1016,34 @@ QHash& Bitstream::getTypeStreamers() { } QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { - static QHash, const TypeStreamer*> enumStreamers; + static QHash, const TypeStreamer*> enumStreamers = createEnumStreamers(); + return enumStreamers; +} + +QHash, const TypeStreamer*> Bitstream::createEnumStreamers() { + QHash, const TypeStreamer*> enumStreamers; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + for (int i = 0; i < metaObject->enumeratorCount(); i++) { + QMetaEnum metaEnum = metaObject->enumerator(i); + const TypeStreamer*& streamer = enumStreamers[QPair(metaEnum.scope(), metaEnum.name())]; + if (!streamer) { + streamer = new EnumTypeStreamer(metaEnum); + } + } + } return enumStreamers; } QHash& Bitstream::getEnumStreamersByName() { - static QHash enumStreamersByName; + static QHash enumStreamersByName = createEnumStreamersByName(); + return enumStreamersByName; +} + +QHash Bitstream::createEnumStreamersByName() { + QHash enumStreamersByName; + foreach (const TypeStreamer* streamer, getEnumStreamers()) { + enumStreamersByName.insert(streamer->getName(), streamer); + } return enumStreamersByName; } @@ -1462,17 +1470,21 @@ QDebug& operator<<(QDebug& debug, const QMetaObject* metaObject) { return debug << (metaObject ? metaObject->className() : "null"); } +EnumTypeStreamer::EnumTypeStreamer(const QMetaObject* metaObject, const char* name) : + _metaObject(metaObject), + _enumName(name), + _name(QByteArray(metaObject->className()) + "::" + name), + _bits(-1) { + + setType(QMetaType::Int); +} + EnumTypeStreamer::EnumTypeStreamer(const QMetaEnum& metaEnum) : + _name(QByteArray(metaEnum.scope()) + "::" + metaEnum.name()), _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); + _bits(-1) { + + setType(QMetaType::Int); } const char* EnumTypeStreamer::getName() const { @@ -1484,10 +1496,21 @@ TypeReader::Type EnumTypeStreamer::getReaderType() const { } int EnumTypeStreamer::getBits() const { + if (_bits == -1) { + int highestValue = 0; + QMetaEnum metaEnum = getMetaEnum(); + for (int j = 0; j < metaEnum.keyCount(); j++) { + highestValue = qMax(highestValue, metaEnum.value(j)); + } + const_cast(this)->_bits = getBitsForHighestValue(highestValue); + } return _bits; } QMetaEnum EnumTypeStreamer::getMetaEnum() const { + if (!_metaEnum.isValid()) { + const_cast(this)->_metaEnum = _metaObject->enumerator(_metaObject->indexOfEnumerator(_enumName)); + } return _metaEnum; } @@ -1497,12 +1520,12 @@ bool EnumTypeStreamer::equal(const QVariant& first, const QVariant& second) cons void EnumTypeStreamer::write(Bitstream& out, const QVariant& value) const { int intValue = value.toInt(); - out.write(&intValue, _bits); + out.write(&intValue, getBits()); } QVariant EnumTypeStreamer::read(Bitstream& in) const { int intValue = 0; - in.read(&intValue, _bits); + in.read(&intValue, getBits()); return intValue; } @@ -1512,7 +1535,7 @@ void EnumTypeStreamer::writeDelta(Bitstream& out, const QVariant& value, const Q out << false; } else { out << true; - out.write(&intValue, _bits); + out.write(&intValue, getBits()); } } @@ -1521,7 +1544,7 @@ void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& in >> changed; if (changed) { int intValue = 0; - in.read(&intValue, _bits); + in.read(&intValue, getBits()); value = intValue; } else { value = reference; @@ -1530,17 +1553,17 @@ void EnumTypeStreamer::readDelta(Bitstream& in, QVariant& value, const QVariant& void EnumTypeStreamer::writeRawDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { int intValue = value.toInt(); - out.write(&intValue, _bits); + out.write(&intValue, getBits()); } void EnumTypeStreamer::readRawDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { int intValue = 0; - in.read(&intValue, _bits); + in.read(&intValue, getBits()); value = intValue; } void EnumTypeStreamer::setEnumValue(QVariant& object, int value, const QHash& mappings) const { - if (_metaEnum.isFlag()) { + if (getMetaEnum().isFlag()) { int combined = 0; for (QHash::const_iterator it = mappings.constBegin(); it != mappings.constEnd(); it++) { if (value & it.key()) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index caf0adf7fc..b0c33754f9 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -427,7 +427,9 @@ private: static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); static QHash, const TypeStreamer*>& getEnumStreamers(); + static QHash, const TypeStreamer*> createEnumStreamers(); static QHash& getEnumStreamersByName(); + static QHash createEnumStreamersByName(); static QVector getPropertyReaders(const QMetaObject* metaObject); }; @@ -938,8 +940,9 @@ public: class EnumTypeStreamer : public TypeStreamer { public: + EnumTypeStreamer(const QMetaObject* metaObject, const char* name); EnumTypeStreamer(const QMetaEnum& metaEnum); - + virtual const char* getName() const; virtual TypeReader::Type getReaderType() const; virtual int getBits() const; @@ -955,8 +958,10 @@ public: private: - QMetaEnum _metaEnum; + const QMetaObject* _metaObject; + const char* _enumName; QByteArray _name; + QMetaEnum _metaEnum; int _bits; }; @@ -1084,14 +1089,15 @@ public: template<> inline void Bitstream::readRawDelta(S::N& value, const S::N& reference) { *this >> value; } #define IMPLEMENT_ENUM_METATYPE(S, N) \ - static int S##N##Bits = registerEnumMetaType(S::staticMetaObject.enumerator( \ - S::staticMetaObject.indexOfEnumerator(#N))); \ + static int S##N##MetaTypeId = registerEnumMetaType(&S::staticMetaObject, #N); \ Bitstream& operator<<(Bitstream& out, const S::N& obj) { \ - return out.write(&obj, S##N##Bits); \ + static int bits = Bitstream::getTypeStreamer(qMetaTypeId())->getBits(); \ + return out.write(&obj, bits); \ } \ Bitstream& operator>>(Bitstream& in, S::N& obj) { \ + static int bits = Bitstream::getTypeStreamer(qMetaTypeId())->getBits(); \ obj = (S::N)0; \ - return in.read(&obj, S##N##Bits); \ + return in.read(&obj, bits); \ } /// Registers a simple type and its streamer. @@ -1103,12 +1109,11 @@ template int registerSimpleMetaType() { } /// Registers an enum type and its streamer. -/// \return the number of bits required to stream the enum -template int registerEnumMetaType(const QMetaEnum& metaEnum) { +/// \return the metatype id +template int registerEnumMetaType(const QMetaObject* metaObject, const char* name) { int type = qRegisterMetaType(); - EnumTypeStreamer* streamer = new EnumTypeStreamer(metaEnum); - Bitstream::registerTypeStreamer(type, streamer); - return streamer->getBits(); + Bitstream::registerTypeStreamer(type, new EnumTypeStreamer(metaObject, name)); + return type; } /// Registers a streamable type and its streamer. From 384fe51937d169f4fd34d7edbf15350e9331e77b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Jun 2014 16:38:52 -0700 Subject: [PATCH 9/9] If we're going to initialize one mapping lazily, we might as well initialize some more that way. --- libraries/metavoxels/src/Bitstream.cpp | 119 ++++++++++++++----------- libraries/metavoxels/src/Bitstream.h | 13 ++- 2 files changed, 71 insertions(+), 61 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 6f4af8ed5f..d9242ad9b7 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -298,7 +298,7 @@ void Bitstream::writeRawDelta(const QObject* value, const QObject* reference) { } const QMetaObject* metaObject = value->metaObject(); _metaObjectStreamer << metaObject; - foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) { propertyWriter.writeDelta(*this, value, reference); } } @@ -476,7 +476,7 @@ Bitstream& Bitstream::operator<<(const QObject* object) { } const QMetaObject* metaObject = object->metaObject(); _metaObjectStreamer << metaObject; - foreach (const PropertyWriter& propertyWriter, getPropertyWriters(metaObject)) { + foreach (const PropertyWriter& propertyWriter, getPropertyWriters().value(metaObject)) { propertyWriter.write(*this, object); } return *this; @@ -561,7 +561,7 @@ Bitstream& Bitstream::operator<(const QMetaObject* metaObject) { if (_metadataType == NO_METADATA) { return *this; } - const QVector& propertyWriters = getPropertyWriters(metaObject); + const QVector& propertyWriters = getPropertyWriters().value(metaObject); *this << propertyWriters.size(); QCryptographicHash hash(QCryptographicHash::Md5); foreach (const PropertyWriter& propertyWriter, propertyWriters) { @@ -595,7 +595,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { qWarning() << "Unknown class name: " << className << "\n"; } if (_metadataType == NO_METADATA) { - objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject)); + objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject)); return *this; } int storedPropertyCount; @@ -619,7 +619,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QCryptographicHash hash(QCryptographicHash::Md5); bool matches = true; if (metaObject) { - const QVector& propertyWriters = getPropertyWriters(metaObject); + const QVector& propertyWriters = getPropertyWriters().value(metaObject); if (propertyWriters.size() == properties.size()) { for (int i = 0; i < propertyWriters.size(); i++) { const PropertyWriter& propertyWriter = propertyWriters.at(i); @@ -638,7 +638,7 @@ Bitstream& Bitstream::operator>(ObjectReader& objectReader) { QByteArray remoteHashResult(localHashResult.size(), 0); read(remoteHashResult.data(), remoteHashResult.size() * BITS_IN_BYTE); if (metaObject && matches && localHashResult == remoteHashResult) { - objectReader = ObjectReader(className, metaObject, getPropertyReaders(metaObject)); + objectReader = ObjectReader(className, metaObject, getPropertyReaders().value(metaObject)); return *this; } } @@ -975,31 +975,6 @@ 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; @@ -1015,7 +990,7 @@ QHash& Bitstream::getTypeStreamers() { return typeStreamers; } -QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { +const QHash, const TypeStreamer*>& Bitstream::getEnumStreamers() { static QHash, const TypeStreamer*> enumStreamers = createEnumStreamers(); return enumStreamers; } @@ -1034,7 +1009,7 @@ QHash, const TypeStreamer*> Bitstream::createEnumS return enumStreamers; } -QHash& Bitstream::getEnumStreamersByName() { +const QHash& Bitstream::getEnumStreamersByName() { static QHash enumStreamersByName = createEnumStreamersByName(); return enumStreamersByName; } @@ -1047,32 +1022,68 @@ QHash Bitstream::createEnumStreamersByName() { return enumStreamersByName; } -QVector Bitstream::getPropertyReaders(const QMetaObject* metaObject) { - QVector propertyReaders; - if (!metaObject) { - return propertyReaders; - } - 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) { - propertyReaders.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); +const QHash >& Bitstream::getPropertyReaders() { + static QHash > propertyReaders = createPropertyReaders(); + return propertyReaders; +} + +QHash > Bitstream::createPropertyReaders() { + QHash > propertyReaders; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + QVector& readers = propertyReaders[metaObject]; + 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) { + readers.append(PropertyReader(TypeReader(QByteArray(), streamer), property)); + } } } return propertyReaders; } +const QHash >& Bitstream::getPropertyWriters() { + static QHash > propertyWriters = createPropertyWriters(); + return propertyWriters; +} + +QHash > Bitstream::createPropertyWriters() { + QHash > propertyWriters; + foreach (const QMetaObject* metaObject, getMetaObjects()) { + QVector& writers = propertyWriters[metaObject]; + 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) { + writers.append(PropertyWriter(property, streamer)); + } + } + } + return propertyWriters; +} + TypeReader::TypeReader(const QByteArray& typeName, const TypeStreamer* streamer) : _typeName(typeName), _streamer(streamer), diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index b0c33754f9..80adfc4e8b 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -400,8 +400,6 @@ private slots: private: - const QVector& getPropertyWriters(const QMetaObject* metaObject); - QDataStream& _underlying; quint8 _byte; int _position; @@ -421,16 +419,17 @@ private: QHash _metaObjectSubstitutions; QHash _typeStreamerSubstitutions; - QHash > _propertyWriters; - static QHash& getMetaObjects(); static QMultiHash& getMetaObjectSubClasses(); static QHash& getTypeStreamers(); - static QHash, const TypeStreamer*>& getEnumStreamers(); + static const QHash, const TypeStreamer*>& getEnumStreamers(); static QHash, const TypeStreamer*> createEnumStreamers(); - static QHash& getEnumStreamersByName(); + static const QHash& getEnumStreamersByName(); static QHash createEnumStreamersByName(); - static QVector getPropertyReaders(const QMetaObject* metaObject); + static const QHash >& getPropertyReaders(); + static QHash > createPropertyReaders(); + static const QHash >& getPropertyWriters(); + static QHash > createPropertyWriters(); }; template inline void Bitstream::writeDelta(const T& value, const T& reference) {