From f910c4471bb02cec6e3545c55ee0e6af69748553 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 2 Mar 2014 17:40:58 -0800 Subject: [PATCH] Distinguish between "hard" and "soft" references to shared objects. Sending bitstreams use soft references and remove their mappings when only soft references remain. --- libraries/metavoxels/src/Bitstream.cpp | 23 +++-- libraries/metavoxels/src/Bitstream.h | 56 ++++++----- libraries/metavoxels/src/SharedObject.cpp | 27 +++-- libraries/metavoxels/src/SharedObject.h | 115 +++++++++++++--------- 4 files changed, 134 insertions(+), 87 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 919bc4cbc8..61e8371652 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -167,11 +167,18 @@ void Bitstream::persistWriteMappings(const WriteMappings& mappings) { _scriptStringStreamer.persistTransientOffsets(mappings.scriptStringOffsets); _sharedObjectStreamer.persistTransientOffsets(mappings.sharedObjectOffsets); - // find out when shared objects' reference counts drop to one in order to clear their mappings - for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); + // find out when shared objects are deleted in order to clear their mappings + for (QHash::const_iterator it = mappings.sharedObjectOffsets.constBegin(); it != mappings.sharedObjectOffsets.constEnd(); it++) { if (it.key()) { - connect(it.key().data(), SIGNAL(referenceCountDroppedToOne()), SLOT(clearSharedObject())); + 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())); + } } } } @@ -465,7 +472,7 @@ Bitstream& Bitstream::operator>(QScriptString& string) { return *this; } -Bitstream& Bitstream::operator<(const SharedObjectPointer& object) { +Bitstream& Bitstream::operator<(const SoftSharedObjectPointer& object) { if (!object) { return *this << (int)0; } @@ -497,10 +504,12 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { return *this; } -void Bitstream::clearSharedObject() { - SharedObjectPointer object(static_cast(sender())); +void Bitstream::clearSharedObject(QObject* object) { object->disconnect(this); - emit sharedObjectCleared(_sharedObjectStreamer.takePersistentID(object)); + int id = _sharedObjectStreamer.takePersistentID(static_cast(object)); + if (id != 0) { + emit sharedObjectCleared(id); + } } void Bitstream::readProperties(QObject* object) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index c06c4c3b5f..fa6975adc1 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(T value) { return _persistentIDs.take(value); } + int takePersistentID(K value) { return _persistentIDs.take(value); } void removePersistentValue(int id) { _persistentValues.remove(id); } - RepeatedValueStreamer& operator<<(T value); - RepeatedValueStreamer& operator>>(T& value); + RepeatedValueStreamer& operator<<(K value); + RepeatedValueStreamer& operator>>(V& value); private: @@ -82,23 +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(); @@ -108,16 +109,17 @@ template inline void RepeatedValueStreamer::persistTransientOffsets( _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(); @@ -128,7 +130,7 @@ template inline void RepeatedValueStreamer::persistTransientValues(c _idStreamer.setBitsFromValue(_lastPersistentID); } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(T value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator<<(K value) { int id = _persistentIDs.value(value); if (id == 0) { int& offset = _transientOffsets[value]; @@ -145,7 +147,7 @@ template inline RepeatedValueStreamer& RepeatedValueStreamer::ope return *this; } -template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(T& value) { +template inline RepeatedValueStreamer& RepeatedValueStreamer::operator>>(V& value) { int id; _idStreamer >> id; if (id <= _lastPersistentID) { @@ -153,7 +155,7 @@ template inline RepeatedValueStreamer& RepeatedValueStreamer::ope } 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); @@ -177,7 +179,7 @@ public: QHash typeStreamerOffsets; QHash attributeOffsets; QHash scriptStringOffsets; - QHash sharedObjectOffsets; + QHash sharedObjectOffsets; }; class ReadMappings { @@ -306,7 +308,7 @@ public: Bitstream& operator<(const QScriptString& string); Bitstream& operator>(QScriptString& string); - Bitstream& operator<(const SharedObjectPointer& object); + Bitstream& operator<(const SoftSharedObjectPointer& object); Bitstream& operator>(SharedObjectPointer& object); signals: @@ -315,7 +317,7 @@ signals: private slots: - void clearSharedObject(); + void clearSharedObject(QObject* object); private: @@ -329,7 +331,7 @@ private: RepeatedValueStreamer _typeStreamerStreamer; RepeatedValueStreamer _attributeStreamer; RepeatedValueStreamer _scriptStringStreamer; - RepeatedValueStreamer _sharedObjectStreamer; + RepeatedValueStreamer _sharedObjectStreamer; QHash > _transientSharedObjects; diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 7e10068afe..c3a224103d 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -18,19 +18,30 @@ REGISTER_META_OBJECT(SharedObject) -SharedObject::SharedObject() : _id(++_lastID), _referenceCount(0) { +static int sharedObjectPointerMetaTypeId = qRegisterMetaType(); +static int softSharedObjectPointerMetaTypeId = qRegisterMetaType(); + +SharedObject::SharedObject() : + _id(++_lastID), + _hardReferenceCount(0), + _softReferenceCount(0) { } -void SharedObject::incrementReferenceCount() { - _referenceCount++; +void SharedObject::decrementHardReferenceCount() { + _hardReferenceCount--; + if (_hardReferenceCount == 0) { + if (_softReferenceCount == 0) { + delete this; + } else { + emit allHardReferencesCleared(this); + } + } } -void SharedObject::decrementReferenceCount() { - if (--_referenceCount == 0) { +void SharedObject::decrementSoftReferenceCount() { + _softReferenceCount--; + if (_hardReferenceCount == 0 && _softReferenceCount == 0) { delete this; - - } else if (_referenceCount == 1) { - emit referenceCountDroppedToOne(); } } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 9895073e44..44bfb73a22 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -27,10 +27,14 @@ public: int getID() { return _id; } - int getReferenceCount() const { return _referenceCount; } - void incrementReferenceCount(); - void decrementReferenceCount(); + int getHardReferenceCount() const { return _hardReferenceCount; } + + void incrementHardReferenceCount() { _hardReferenceCount++; } + void decrementHardReferenceCount(); + void incrementSoftReferenceCount() { _softReferenceCount++; } + void decrementSoftReferenceCount(); + /// Creates a new clone of this object. virtual SharedObject* clone() const; @@ -42,23 +46,29 @@ public: signals: - /// Emitted when the reference count drops to one. - void referenceCountDroppedToOne(); + /// Emitted when only soft reference counts remain. + void allHardReferencesCleared(QObject* object); private: int _id; - int _referenceCount; + int _hardReferenceCount; + int _softReferenceCount; 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); + SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other); + template SharedObjectPointerTemplate( + const SharedObjectPointerTemplate& other); ~SharedObjectPointerTemplate(); T* data() const { return _data; } @@ -66,7 +76,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(); @@ -75,81 +85,91 @@ 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); + SharedObjectPointerTemplate& operator=(T* data); + SharedObjectPointerTemplate& operator=(const SharedObjectPointerTemplate& other) { + return *this = other.data(); } + template SharedObjectPointerTemplate& operator=( + const SharedObjectPointerTemplate& other) { return *this = other.data(); } - bool operator==(const SharedObjectPointerTemplate& other) const { return _data == other._data; } - bool operator!=(const SharedObjectPointerTemplate& other) const { return _data != other._data; } + bool operator==(T* data) const { return _data == data; } + bool operator!=(T* data) const { return _data != 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->incrementReferenceCount(); + (_data->*Inc)(); } } -template inline SharedObjectPointerTemplate::SharedObjectPointerTemplate(const SharedObjectPointerTemplate& other) : - _data(other._data) { - +template inline + SharedObjectPointerTemplate::SharedObjectPointerTemplate( + const SharedObjectPointerTemplate& other) : _data(other.data()) { if (_data) { - _data->incrementReferenceCount(); + (_data->*Inc)(); } } -template inline SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { +template template inline + SharedObjectPointerTemplate::SharedObjectPointerTemplate( + const SharedObjectPointerTemplate& other) : _data(other.data()) { if (_data) { - _data->decrementReferenceCount(); + (_data->*Inc)(); } } -template inline bool SharedObjectPointerTemplate::detach() { - if (_data && _data->getReferenceCount() > 1) { - _data->decrementReferenceCount(); - (_data = _data->clone())->incrementReferenceCount(); +template inline + SharedObjectPointerTemplate::~SharedObjectPointerTemplate() { + if (_data) { + (_data->*Dec)(); + } +} + +template inline bool SharedObjectPointerTemplate::detach() { + if (_data && _data->getHardReferenceCount() > 1) { + (_data->*Dec)(); + ((_data = _data->clone())->*Inc)(); return true; } return false; } -template inline void SharedObjectPointerTemplate::reset() { +template inline void SharedObjectPointerTemplate::reset() { if (_data) { - _data->decrementReferenceCount(); + (_data->*Dec)(); } _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->decrementReferenceCount(); + (_data->*Dec)(); } if ((_data = data)) { - _data->incrementReferenceCount(); + (_data->*Inc)(); } return *this; } -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) { +template uint qHash( + const SharedObjectPointerTemplate& pointer, uint seed = 0) { return qHash(pointer.data(), seed); } @@ -161,6 +181,11 @@ 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