Browse Source

added scoped-based destruction for services

pull/2/head
Skycoder42 7 years ago
parent
commit
4d28010979
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 84
      src/mvvmcore/serviceregistry.cpp
  2. 57
      src/mvvmcore/serviceregistry.h
  3. 13
      src/mvvmcore/serviceregistry_p.h

84
src/mvvmcore/serviceregistry.cpp

@ -15,9 +15,19 @@ Q_GLOBAL_STATIC_WITH_ARGS(ServiceRegistry, _instance,
ServiceRegistry::ServiceRegistry(ServiceRegistryPrivate *d_ptr) : ServiceRegistry::ServiceRegistry(ServiceRegistryPrivate *d_ptr) :
d(d_ptr) d(d_ptr)
{} {
// register quit scope cleanup
QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this](){
d->destroyServices(DestroyOnAppQuit);
});
// register destroy scope cleanup
qAddPostRoutine(&ServiceRegistryPrivate::appDestroyedHook);
}
ServiceRegistry::~ServiceRegistry() = default; ServiceRegistry::~ServiceRegistry()
{
d->destroyServices(DestroyOnRegistryDestroy);
}
ServiceRegistry *ServiceRegistry::instance() ServiceRegistry *ServiceRegistry::instance()
{ {
@ -30,20 +40,30 @@ bool ServiceRegistry::isRegistered(const QByteArray &iid) const
return d->services.contains(iid); return d->services.contains(iid);
} }
void ServiceRegistry::registerService(const QByteArray &iid, const QMetaObject *metaObject, bool weak) void ServiceRegistry::registerService(const QByteArray &iid, const QMetaObject *metaObject, bool weak, DestructionScope scope)
{ {
QMutexLocker _(&d->serviceMutex); QMutexLocker _(&d->serviceMutex);
if(d->serviceBlocked(iid)) if(d->serviceBlocked(iid))
throw ServiceExistsException(iid); throw ServiceExistsException(iid);
d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::MetaServiceInfo>::create(metaObject, weak)); d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::MetaServiceInfo>::create(metaObject, weak, scope));
} }
void ServiceRegistry::registerService(const QByteArray &iid, const std::function<QObject*(const QObjectList &)> &fn, QByteArrayList injectables, bool weak) void ServiceRegistry::registerService(const QByteArray &iid, const QMetaObject *metaObject, bool weak)
{
registerService(iid, metaObject, weak, DestroyOnAppDestroy);
}
void ServiceRegistry::registerService(const QByteArray &iid, const std::function<QObject *(const QObjectList &)> &fn, QByteArrayList injectables, bool weak, DestructionScope scope)
{ {
QMutexLocker _(&d->serviceMutex); QMutexLocker _(&d->serviceMutex);
if(d->serviceBlocked(iid)) if(d->serviceBlocked(iid))
throw ServiceExistsException(iid); throw ServiceExistsException(iid);
d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::FnServiceInfo>::create(fn, injectables, weak)); d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::FnServiceInfo>::create(fn, std::move(injectables), weak, scope));
}
void ServiceRegistry::registerService(const QByteArray &iid, const std::function<QObject*(const QObjectList &)> &fn, QByteArrayList injectables, bool weak)
{
registerService(iid, fn, std::move(injectables), weak, DestroyOnAppDestroy);
} }
QObject *ServiceRegistry::serviceObj(const QByteArray &iid) QObject *ServiceRegistry::serviceObj(const QByteArray &iid)
@ -140,16 +160,37 @@ void ServiceRegistryPrivate::injectLocked(QObject *object)
} }
} }
void ServiceRegistryPrivate::destroyServices(ServiceRegistry::DestructionScope scope)
{
QMutexLocker _(&serviceMutex);
logDebug() << "Beginning destruction for services in scope:" << scope;
for(auto it = services.begin(); it != services.end();) {
if(it.value()->needsDestroy(scope)) {
logDebug() << "Destroying service:" << it.key();
it = services.erase(it);
} else
it++;
}
logDebug() << "Finished destruction for services in scope:" << scope;
}
void ServiceRegistryPrivate::appDestroyedHook()
{
if(_instance.exists() && !_instance.isDestroyed())
_instance->d->destroyServices(ServiceRegistry::DestroyOnAppDestroy);
}
ServiceRegistryPrivate::ServiceInfo::ServiceInfo(bool weak) :
_weak{weak}
ServiceRegistryPrivate::ServiceInfo::ServiceInfo(bool weak, ServiceRegistry::DestructionScope scope) :
_weak{weak},
_scope{scope}
{} {}
ServiceRegistryPrivate::ServiceInfo::~ServiceInfo() ServiceRegistryPrivate::ServiceInfo::~ServiceInfo()
{ {
if(_instance) { if(_instance && _scope != ServiceRegistry::DestroyNever) {
if(QCoreApplication::closingDown()) if(_closingDown)
delete _instance; delete _instance;
else else
QMetaObject::invokeMethod(_instance, "deleteLater"); QMetaObject::invokeMethod(_instance, "deleteLater");
@ -161,6 +202,15 @@ bool ServiceRegistryPrivate::ServiceInfo::replaceable() const
return _weak && !_instance; return _weak && !_instance;
} }
bool ServiceRegistryPrivate::ServiceInfo::needsDestroy(ServiceRegistry::DestructionScope scope) const
{
if(_scope <= scope) {
_closingDown = true;
return true;
} else
return false;
}
QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d, const QByteArray &iid) QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d, const QByteArray &iid)
{ {
if(!_instance) { if(!_instance) {
@ -178,10 +228,10 @@ QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d
ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(std::function<QObject*(QObjectList)> creator, QByteArrayList injectables, bool weak) : ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(std::function<QObject*(QObjectList)> creator, QByteArrayList injectables, bool weak, ServiceRegistry::DestructionScope scope) :
ServiceInfo(weak), ServiceInfo{weak, scope},
creator(std::move(creator)), creator{std::move(creator)},
injectables(std::move(injectables)) injectables{std::move(injectables)}
{} {}
QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate *d) const QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate *d) const
@ -199,9 +249,9 @@ QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate
ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject, bool weak) : ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject, bool weak, ServiceRegistry::DestructionScope scope) :
ServiceInfo(weak), ServiceInfo{weak, scope},
metaObject(metaObject) metaObject{metaObject}
{} {}
QObject *ServiceRegistryPrivate::MetaServiceInfo::construct(ServiceRegistryPrivate *d) const QObject *ServiceRegistryPrivate::MetaServiceInfo::construct(ServiceRegistryPrivate *d) const

57
src/mvvmcore/serviceregistry.h

@ -17,6 +17,14 @@ class ServiceRegistryPrivate;
class Q_MVVMCORE_EXPORT ServiceRegistry class Q_MVVMCORE_EXPORT ServiceRegistry
{ {
public: public:
enum DestructionScope {
DestroyOnAppQuit = 1,
DestroyOnAppDestroy = 2,
DestroyOnRegistryDestroy = 3,
DestroyNever = 127
};
//! @private //! @private
ServiceRegistry(ServiceRegistryPrivate *d_ptr); ServiceRegistry(ServiceRegistryPrivate *d_ptr);
~ServiceRegistry(); ~ServiceRegistry();
@ -32,32 +40,41 @@ public:
//! Register a service for its interface via the type //! Register a service for its interface via the type
template <typename TInterface, typename TService> template <typename TInterface, typename TService>
void registerInterface(bool weak = false); void registerInterface(bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service for its interface via a constructor function //! Register a service for its interface via a constructor function
template <typename TInterface, typename TService, typename TFunc> template <typename TInterface, typename TService, typename TFunc>
void registerInterface(TFunc fn, bool weak = false); void registerInterface(TFunc fn, bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service for its interface via an already existing instance //! Register a service for its interface via an already existing instance
template <typename TInterface, typename TService> template <typename TInterface, typename TService>
void registerInterface(TService *service, bool weak = false); void registerInterface(TService *service, bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service via its type //! Register a service via its type
template <typename TService> template <typename TService>
void registerObject(bool weak = false); void registerObject(bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service via a constructor function //! Register a service via a constructor function
template <typename TService, typename TFunc> template <typename TService, typename TFunc>
void registerObject(TFunc fn, bool weak = false); void registerObject(TFunc fn, bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service via an already existing instance //! Register a service via an already existing instance
template <typename TService> template <typename TService>
void registerObject(TService *service, bool weak = false); void registerObject(TService *service, bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service by an iid via their metadata //! Register a service by an iid via their metadata
void registerService(const QByteArray &iid, void registerService(const QByteArray &iid,
const QMetaObject *metaObject, const QMetaObject *metaObject,
bool weak = false); bool weak,
DestructionScope scope);
void registerService(const QByteArray &iid,
const QMetaObject *metaObject,
bool weak = false); //MAJOR merge methods
//! Register a service by an iid via a generalized constructor function //! Register a service by an iid via a generalized constructor function
void registerService(const QByteArray &iid, void registerService(const QByteArray &iid,
const std::function<QObject*(const QObjectList &)> &fn, const std::function<QObject*(const QObjectList &)> &fn,
QByteArrayList injectables, QByteArrayList injectables,
bool weak = false); bool weak,
DestructionScope scope);
void registerService(const QByteArray &iid,
const std::function<QObject*(const QObjectList &)> &fn,
QByteArrayList injectables,
bool weak = false);//MAJOR merge methods
//! Returns the service for the given interface //! Returns the service for the given interface
template <typename TInterface> template <typename TInterface>
@ -152,29 +169,29 @@ bool ServiceRegistry::isRegistered() const
Q_ASSERT_X(qobject_interface_iid<TInterface*>(), Q_FUNC_INFO, "TInterface must be registered with Q_DECLARE_INTERFACE"); Q_ASSERT_X(qobject_interface_iid<TInterface*>(), Q_FUNC_INFO, "TInterface must be registered with Q_DECLARE_INTERFACE");
template<typename TInterface, typename TService> template<typename TInterface, typename TService>
void ServiceRegistry::registerInterface(bool weak) void ServiceRegistry::registerInterface(bool weak, DestructionScope scope)
{ {
QTMVVM_SERVICE_ASSERT(TInterface, TService) QTMVVM_SERVICE_ASSERT(TInterface, TService)
registerService(qobject_interface_iid<TInterface*>(), &TService::staticMetaObject, weak); registerService(qobject_interface_iid<TInterface*>(), &TService::staticMetaObject, weak, scope);
} }
template <typename TInterface, typename TService, typename TFunc> template <typename TInterface, typename TService, typename TFunc>
void ServiceRegistry::registerInterface(TFunc fn, bool weak) void ServiceRegistry::registerInterface(TFunc fn, bool weak, DestructionScope scope)
{ {
QTMVVM_SERVICE_ASSERT(TInterface, TService) QTMVVM_SERVICE_ASSERT(TInterface, TService)
QByteArrayList injectables; QByteArrayList injectables;
auto packed_fn = __helpertypes::pack_function(std::move(fn), injectables); auto packed_fn = __helpertypes::pack_function(std::move(fn), injectables);
registerService(qobject_interface_iid<TInterface*>(), packed_fn, injectables, weak); registerService(qobject_interface_iid<TInterface*>(), packed_fn, injectables, weak, scope);
} }
template<typename TInterface, typename TService> template<typename TInterface, typename TService>
void ServiceRegistry::registerInterface(TService *service, bool weak) void ServiceRegistry::registerInterface(TService *service, bool weak, DestructionScope scope)
{ {
QTMVVM_SERVICE_ASSERT(TInterface, TService) QTMVVM_SERVICE_ASSERT(TInterface, TService)
registerService(qobject_interface_iid<TInterface*>(), [service](const QObjectList &params) -> QObject* { registerService(qobject_interface_iid<TInterface*>(), [service](const QObjectList &params) -> QObject* {
Q_UNUSED(params); Q_UNUSED(params);
return service; return service;
}, QByteArrayList(), weak); }, QByteArrayList(), weak, scope);
} }
#undef QTMVVM_SERVICE_ASSERT #undef QTMVVM_SERVICE_ASSERT
@ -182,29 +199,29 @@ void ServiceRegistry::registerInterface(TService *service, bool weak)
static_assert(__helpertypes::is_qobj<tsvc>::value, "TService must be a qobject class"); static_assert(__helpertypes::is_qobj<tsvc>::value, "TService must be a qobject class");
template<typename TService> template<typename TService>
void ServiceRegistry::registerObject(bool weak) void ServiceRegistry::registerObject(bool weak, DestructionScope scope)
{ {
QTMVVM_SERVICE_ASSERT(TService) QTMVVM_SERVICE_ASSERT(TService)
registerService(__helpertypes::qobject_iid<TService*>(), &TService::staticMetaObject, weak); registerService(__helpertypes::qobject_iid<TService*>(), &TService::staticMetaObject, weak, scope);
} }
template<typename TService, typename TFunc> template<typename TService, typename TFunc>
void ServiceRegistry::registerObject(TFunc fn, bool weak) void ServiceRegistry::registerObject(TFunc fn, bool weak, DestructionScope scope)
{ {
QTMVVM_SERVICE_ASSERT(TService) QTMVVM_SERVICE_ASSERT(TService)
QByteArrayList injectables; QByteArrayList injectables;
auto packed_fn = __helpertypes::pack_function(std::move(fn), injectables); auto packed_fn = __helpertypes::pack_function(std::move(fn), injectables);
registerService(__helpertypes::qobject_iid<TService*>(), packed_fn, injectables, weak); registerService(__helpertypes::qobject_iid<TService*>(), packed_fn, injectables, weak, scope);
} }
template<typename TService> template<typename TService>
void ServiceRegistry::registerObject(TService *service, bool weak) void ServiceRegistry::registerObject(TService *service, bool weak, DestructionScope scope)
{ {
QTMVVM_SERVICE_ASSERT(TService) QTMVVM_SERVICE_ASSERT(TService)
registerService(__helpertypes::qobject_iid<TService*>(), [service](const QObjectList &params) -> QObject* { registerService(__helpertypes::qobject_iid<TService*>(), [service](const QObjectList &params) -> QObject* {
Q_UNUSED(params); Q_UNUSED(params);
return service; return service;
}, QByteArrayList(), weak); }, QByteArrayList(), weak, scope);
} }
#undef QTMVVM_SERVICE_ASSERT #undef QTMVVM_SERVICE_ASSERT

13
src/mvvmcore/serviceregistry_p.h

@ -15,10 +15,11 @@ public:
class ServiceInfo { class ServiceInfo {
Q_DISABLE_COPY(ServiceInfo) Q_DISABLE_COPY(ServiceInfo)
public: public:
ServiceInfo(bool weak); ServiceInfo(bool weak, ServiceRegistry::DestructionScope scope);
virtual ~ServiceInfo(); virtual ~ServiceInfo();
bool replaceable() const; bool replaceable() const;
bool needsDestroy(ServiceRegistry::DestructionScope scope) const;
QObject *instance(ServiceRegistryPrivate *d, const QByteArray &iid); QObject *instance(ServiceRegistryPrivate *d, const QByteArray &iid);
protected: protected:
@ -26,12 +27,14 @@ public:
private: private:
const bool _weak; const bool _weak;
const ServiceRegistry::DestructionScope _scope;
QObject *_instance = nullptr; QObject *_instance = nullptr;
mutable bool _closingDown = false;
}; };
class FnServiceInfo : public ServiceInfo { class FnServiceInfo : public ServiceInfo {
public: public:
FnServiceInfo(std::function<QObject*(QObjectList)> creator, QByteArrayList injectables, bool weak); FnServiceInfo(std::function<QObject*(QObjectList)> creator, QByteArrayList injectables, bool weak, ServiceRegistry::DestructionScope scope);
protected: protected:
QObject *construct(ServiceRegistryPrivate *d) const final; QObject *construct(ServiceRegistryPrivate *d) const final;
@ -43,7 +46,7 @@ public:
class MetaServiceInfo : public ServiceInfo { class MetaServiceInfo : public ServiceInfo {
public: public:
MetaServiceInfo(const QMetaObject *metaObject, bool weak); MetaServiceInfo(const QMetaObject *metaObject, bool weak, ServiceRegistry::DestructionScope scope);
protected: protected:
QObject *construct(ServiceRegistryPrivate *d) const final; QObject *construct(ServiceRegistryPrivate *d) const final;
@ -58,6 +61,10 @@ public:
bool serviceBlocked(const QByteArray &iid) const; bool serviceBlocked(const QByteArray &iid) const;
QObject *constructInjectedLocked(const QMetaObject *metaObject, QObject *parent); QObject *constructInjectedLocked(const QMetaObject *metaObject, QObject *parent);
void injectLocked(QObject *object); void injectLocked(QObject *object);
void destroyServices(ServiceRegistry::DestructionScope scope);
static void appDestroyedHook();
}; };
} }

Loading…
Cancel
Save