diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 61e8371652..11deb95b14 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -168,21 +168,18 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { _sharedObjectStreamer.persistTransientOffsets(mappings.sharedObjectOffsets); // find out when shared objects are deleted in order to clear their mappings - for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); + for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); it != mappings.sharedObjectOffsets.constEnd(); it++) { if (it.key()) { - if (it.key()->getHardReferenceCount() > 0) { - connect(it.key().data(), SIGNAL(allHardReferencesCleared(QObject*)), - SLOT(clearSharedObject(QObject*))); - } else { - // invoke on a queued connection so as to run after any other mappings are persisted - QMetaObject::invokeMethod(this, "clearSharedObject", Qt::QueuedConnection, - Q_ARG(QObject*, it.key().data())); - } + connect(it.key().data(), SIGNAL(destroyed(QObject*)), SLOT(clearSharedObject(QObject*))); } } } +void Bitstream::persistAndResetWriteMappings() { + persistWriteMappings(getAndResetWriteMappings()); +} + Bitstream::ReadMappings Bitstream::getAndResetReadMappings() { ReadMappings mappings = { _metaObjectStreamer.getAndResetTransientValues(), _typeStreamerStreamer.getAndResetTransientValues(), @@ -200,6 +197,10 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) { _sharedObjectStreamer.persistTransientValues(mappings.sharedObjectValues); } +void Bitstream::persistAndResetReadMappings() { + persistReadMappings(getAndResetReadMappings()); +} + Bitstream& Bitstream::operator<<(bool value) { if (value) { _byte |= (1 << _position); @@ -472,7 +473,7 @@ Bitstream& Bitstream::operator>(QScriptString& string) { return *this; } -Bitstream& Bitstream::operator<(const SoftSharedObjectPointer& object) { +Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { if (!object) { return *this << (int)0; } @@ -505,7 +506,6 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { } void Bitstream::clearSharedObject(QObject* object) { - object->disconnect(this); int id = _sharedObjectStreamer.takePersistentID(static_cast(object)); if (id != 0) { emit sharedObjectCleared(id); diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index fa6975adc1..9c42828a66 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -55,26 +55,26 @@ private: /// Provides a means to stream repeated values efficiently. The value is first streamed along with a unique ID. When /// subsequently streamed, only the ID is sent. -template class RepeatedValueStreamer { +template class RepeatedValueStreamer { public: RepeatedValueStreamer(Bitstream& stream) : _stream(stream), _idStreamer(stream), _lastPersistentID(0), _lastTransientOffset(0) { } - QHash getAndResetTransientOffsets(); + QHash getAndResetTransientOffsets(); - void persistTransientOffsets(const QHash& transientOffsets); + void persistTransientOffsets(const QHash& transientOffsets); - QHash getAndResetTransientValues(); + QHash getAndResetTransientValues(); - void persistTransientValues(const QHash& transientValues); + void persistTransientValues(const QHash& transientValues); - int takePersistentID(K value) { return _persistentIDs.take(value); } + int takePersistentID(P value) { return _persistentIDs.take(value); } - void removePersistentValue(int id) { _persistentValues.remove(id); } + void removePersistentValue(int id) { _persistentIDs.remove(_persistentValues.take(id)); } - RepeatedValueStreamer& operator<<(K value); - RepeatedValueStreamer& operator>>(V& value); + RepeatedValueStreamer& operator<<(T value); + RepeatedValueStreamer& operator>>(T& value); private: @@ -82,24 +82,24 @@ private: IDStreamer _idStreamer; int _lastPersistentID; int _lastTransientOffset; - QHash _persistentIDs; - QHash _transientOffsets; - QHash _persistentValues; - QHash _transientValues; + QHash _persistentIDs; + QHash _transientOffsets; + QHash _persistentValues; + QHash _transientValues; }; -template inline QHash RepeatedValueStreamer::getAndResetTransientOffsets() { - QHash transientOffsets; +template inline QHash RepeatedValueStreamer::getAndResetTransientOffsets() { + QHash transientOffsets; _transientOffsets.swap(transientOffsets); _lastTransientOffset = 0; _idStreamer.setBitsFromValue(_lastPersistentID); return transientOffsets; } -template inline void RepeatedValueStreamer::persistTransientOffsets( - const QHash& transientOffsets) { +template inline void RepeatedValueStreamer::persistTransientOffsets( + const QHash& transientOffsets) { int oldLastPersistentID = _lastPersistentID; - for (typename QHash::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) { + for (typename QHash::const_iterator it = transientOffsets.constBegin(); it != transientOffsets.constEnd(); it++) { int& id = _persistentIDs[it.key()]; if (id == 0) { id = oldLastPersistentID + it.value(); @@ -109,17 +109,17 @@ template inline void RepeatedValueStreamer::persistTrans _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline QHash RepeatedValueStreamer::getAndResetTransientValues() { - QHash transientValues; +template inline QHash RepeatedValueStreamer::getAndResetTransientValues() { + QHash transientValues; _transientValues.swap(transientValues); _idStreamer.setBitsFromValue(_lastPersistentID); return transientValues; } -template inline void RepeatedValueStreamer::persistTransientValues( - const QHash& transientValues) { +template inline void RepeatedValueStreamer::persistTransientValues( + const QHash& transientValues) { int oldLastPersistentID = _lastPersistentID; - for (typename QHash::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) { + for (typename QHash::const_iterator it = transientValues.constBegin(); it != transientValues.constEnd(); it++) { int& id = _persistentIDs[it.value()]; if (id == 0) { id = oldLastPersistentID + it.key(); @@ -130,7 +130,7 @@ template inline void RepeatedValueStreamer::persistTrans _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(K value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(T value) { int id = _persistentIDs.value(value); if (id == 0) { int& offset = _transientOffsets[value]; @@ -147,7 +147,7 @@ template inline RepeatedValueStreamer& RepeatedValueStre return *this; } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(V& value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(T& value) { int id; _idStreamer >> id; if (id <= _lastPersistentID) { @@ -155,7 +155,7 @@ template inline RepeatedValueStreamer& RepeatedValueStre } else { int offset = id - _lastPersistentID; - typename QHash::iterator it = _transientValues.find(offset); + typename QHash::iterator it = _transientValues.find(offset); if (it == _transientValues.end()) { _stream > value; _transientValues.insert(offset, value); @@ -179,7 +179,7 @@ public: QHash typeStreamerOffsets; QHash attributeOffsets; QHash scriptStringOffsets; - QHash sharedObjectOffsets; + QHash sharedObjectOffsets; }; class ReadMappings { @@ -230,12 +230,18 @@ public: /// Persists a set of write mappings recorded earlier. void persistWriteMappings(const WriteMappings& mappings); + /// Immediately persists and resets the write mappings. + void persistAndResetWriteMappings(); + /// Returns the set of transient mappings gathered during reading and resets them. ReadMappings getAndResetReadMappings(); /// Persists a set of read mappings recorded earlier. void persistReadMappings(const ReadMappings& mappings); + /// Immediately persists and resets the read mappings. + void persistAndResetReadMappings(); + /// Removes a shared object from the read mappings. void clearSharedObject(int id) { _sharedObjectStreamer.removePersistentValue(id); } @@ -308,7 +314,7 @@ public: Bitstream& operator<(const QScriptString& string); Bitstream& operator>(QScriptString& string); - Bitstream& operator<(const SoftSharedObjectPointer& object); + Bitstream& operator<(const SharedObjectPointer& object); Bitstream& operator>(SharedObjectPointer& object); signals: @@ -331,7 +337,7 @@ private: RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; - RepeatedValueStreamer _sharedObjectStreamer; + RepeatedValueStreamer _sharedObjectStreamer; QHash > _transientSharedObjects; diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 0c7b8ce8ab..052f480fcf 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -587,6 +587,7 @@ void ReliableChannel::sendMessage(const QVariant& message) { _dataStream << (quint32)0; _bitstream << message; _bitstream.flush(); + _bitstream.persistAndResetWriteMappings(); quint32 length = _buffer.pos() - placeholder; _buffer.writeBytes(placeholder, sizeof(quint32), (const char*)&length); @@ -745,6 +746,7 @@ void ReliableChannel::readData(QDataStream& in) { QVariant message; _bitstream >> message; _bitstream.reset(); + _bitstream.persistAndResetReadMappings(); emit receivedMessage(message); continue; } diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index b542299d00..b67354828a 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -18,29 +18,15 @@ REGISTER_META_OBJECT(SharedObject) -static int sharedObjectPointerMetaTypeId = qRegisterMetaType(); -static int softSharedObjectPointerMetaTypeId = qRegisterMetaType(); - -SharedObject::SharedObject() : - _id(++_lastID), - _hardReferenceCount(0), - _softReferenceCount(0) { +SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) { } -void SharedObject::decrementHardReferenceCount() { - _hardReferenceCount--; - if (_hardReferenceCount == 0) { - if (_softReferenceCount == 0) { - delete this; - } else { - emit allHardReferencesCleared(this); - } - } +void SharedObject::incrementReferenceCount() { + _referenceCount++; } -void SharedObject::decrementSoftReferenceCount() { - _softReferenceCount--; - if (_hardReferenceCount == 0 && _softReferenceCount == 0) { +void SharedObject::decrementReferenceCount() { + if (--_referenceCount == 0) { delete this; } } @@ -62,13 +48,13 @@ SharedObject* SharedObject::clone() const { } bool SharedObject::equals(const SharedObject* other) const { - // default behavior is to compare the properties if (!other) { return false; } if (other == this) { return true; } + // default behavior is to compare the properties const QMetaObject* metaObject = this->metaObject(); if (metaObject != other->metaObject()) { return false; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index f83079b0fa..344a77cc94 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -27,14 +27,10 @@ public: int getID() { return _id; } - int getHardReferenceCount() const { return _hardReferenceCount; } - - void incrementHardReferenceCount() { _hardReferenceCount++; } - void decrementHardReferenceCount(); + int getReferenceCount() const { return _referenceCount; } + void incrementReferenceCount(); + void decrementReferenceCount(); - void incrementSoftReferenceCount() { _softReferenceCount++; } - void decrementSoftReferenceCount(); - /// Creates a new clone of this object. virtual SharedObject* clone() const; @@ -44,31 +40,20 @@ public: // Dumps the contents of this object to the debug output. virtual void dump(QDebug debug = QDebug(QtDebugMsg)) const; -signals: - - /// Emitted when only soft reference counts remain. - void allHardReferencesCleared(QObject* object); - private: int _id; - int _hardReferenceCount; - int _softReferenceCount; + int _referenceCount; static int _lastID; }; -typedef void (SharedObject::*SharedObjectFn)(); - /// A pointer to a shared object. -template class SharedObjectPointerTemplate { +template class SharedObjectPointerTemplate { public: SharedObjectPointerTemplate(T* data = NULL); - SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); - template SharedObjectPointerTemplate( - const SharedObjectPointerTemplate& other); + SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); ~SharedObjectPointerTemplate(); T* data() const { return _data; } @@ -76,7 +61,7 @@ public: /// "Detaches" this object, making a new copy if its reference count is greater than one. bool detach(); - void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } + void swap(SharedObjectPointerTemplate& other) { qSwap(_data, other._data); } void reset(); @@ -85,96 +70,86 @@ public: T& operator*() const { return *_data; } T* operator->() const { return _data; } - template SharedObjectPointerTemplate staticCast() const; + template SharedObjectPointerTemplate staticCast() const; - SharedObjectPointerTemplate& operator=(T* data); - SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other) { - return *this = other.data(); } - template SharedObjectPointerTemplate& operator=( - const SharedObjectPointerTemplate& other) { return *this = other.data(); } + SharedObjectPointerTemplate& operator=(T* data); + SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other); - bool operator==(T* data) const { return _data == data; } - bool operator!=(T* data) const { return _data != data; } + bool operator==(const SharedObjectPointerTemplate& other) const { return _data == other._data; } + bool operator!=(const SharedObjectPointerTemplate& other) const { return _data != other._data; } - template bool operator==( - const SharedObjectPointerTemplate& other) const { return _data == other.data(); } - template bool operator!=( - const SharedObjectPointerTemplate& other) const { return _data != other.data(); } - private: T* _data; }; -template inline - SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { +template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(T* data) : _data(data) { if (_data) { - (_data->*Inc)(); + _data->incrementReferenceCount(); } } -template inline - SharedObjectPointerTemplate::SharedObjectPointerTemplate( - const SharedObjectPointerTemplate& other) : _data(other.data()) { +template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other) : + _data(other._data) { + if (_data) { - (_data->*Inc)(); + _data->incrementReferenceCount(); } } -template template inline - SharedObjectPointerTemplate::SharedObjectPointerTemplate( - const SharedObjectPointerTemplate& other) : _data(other.data()) { +template inline SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { if (_data) { - (_data->*Inc)(); + _data->decrementReferenceCount(); } } -template inline - SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { - if (_data) { - (_data->*Dec)(); - } -} - -template inline bool SharedObjectPointerTemplate::detach() { - if (_data && _data->getHardReferenceCount() > 1) { - (_data->*Dec)(); - ((_data = _data->clone())->*Inc)(); +template inline bool SharedObjectPointerTemplate::detach() { + if (_data && _data->getReferenceCount() > 1) { + _data->decrementReferenceCount(); + (_data = _data->clone())->incrementReferenceCount(); return true; } return false; } -template inline void SharedObjectPointerTemplate::reset() { +template inline void SharedObjectPointerTemplate::reset() { if (_data) { - (_data->*Dec)(); + _data->decrementReferenceCount(); } _data = NULL; } -template template inline - SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { - return SharedObjectPointerTemplate(static_cast(_data)); +template template inline SharedObjectPointerTemplate SharedObjectPointerTemplate::staticCast() const { + return SharedObjectPointerTemplate(static_cast(_data)); } -template inline - SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { +template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=(T* data) { if (_data) { - (_data->*Dec)(); + _data->decrementReferenceCount(); } if ((_data = data)) { - (_data->*Inc)(); + _data->incrementReferenceCount(); } return *this; } -template uint qHash( - const SharedObjectPointerTemplate& pointer, uint seed = 0) { +template inline SharedObjectPointerTemplate& SharedObjectPointerTemplate::operator=( + const SharedObjectPointerTemplate& other) { + if (_data) { + _data->decrementReferenceCount(); + } + if ((_data = other._data)) { + _data->incrementReferenceCount(); + } + return *this; +} + +template uint qHash(const SharedObjectPointerTemplate& pointer, uint seed = 0) { return qHash(pointer.data(), seed); } -template bool equals( - const SharedObjectPointerTemplate& first, const SharedObjectPointerTemplate& second) { +template bool equals(const SharedObjectPointerTemplate& first, + const SharedObjectPointerTemplate& second) { return first ? first->equals(second) : !second; } @@ -186,11 +161,6 @@ typedef QSet SharedObjectSet; Q_DECLARE_METATYPE(SharedObjectSet) -typedef SharedObjectPointerTemplate SoftSharedObjectPointer; - -Q_DECLARE_METATYPE(SoftSharedObjectPointer) - /// Allows editing shared object instances. class SharedObjectEditor : public QWidget { Q_OBJECT diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index f06658da68..b1f3315bc0 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -10,6 +10,8 @@ #include +#include + #include "MetavoxelTests.h" REGISTER_META_OBJECT(TestSharedObjectA) @@ -245,6 +247,9 @@ void Endpoint::sendDatagram(const QByteArray& datagram) { } void Endpoint::handleHighPriorityMessage(const QVariant& message) { + if (message.userType() == ClearSharedObjectMessage::Type) { + return; + } if (_other->_highPriorityMessagesSent.isEmpty()) { throw QString("Received unsent/already sent high priority message."); } @@ -274,6 +279,10 @@ void Endpoint::readMessage(Bitstream& in) { } void Endpoint::handleReliableMessage(const QVariant& message) { + if (message.userType() == ClearSharedObjectMessage::Type || + message.userType() == ClearMainChannelSharedObjectMessage::Type) { + return; + } if (_other->_reliableMessagesSent.isEmpty()) { throw QString("Received unsent/already sent reliable message."); }