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) :
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()
{
@ -30,20 +40,30 @@ bool ServiceRegistry::isRegistered(const QByteArray &iid) const
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);
if(d->serviceBlocked(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);
if(d->serviceBlocked(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)
@ -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()
{
if(_instance) {
if(QCoreApplication::closingDown())
if(_instance && _scope != ServiceRegistry::DestroyNever) {
if(_closingDown)
delete _instance;
else
QMetaObject::invokeMethod(_instance, "deleteLater");
@ -161,6 +202,15 @@ bool ServiceRegistryPrivate::ServiceInfo::replaceable() const
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)
{
if(!_instance) {
@ -178,10 +228,10 @@ QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d
ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(std::function<QObject*(QObjectList)> creator, QByteArrayList injectables, bool weak) :
ServiceInfo(weak),
creator(std::move(creator)),
injectables(std::move(injectables))
ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(std::function<QObject*(QObjectList)> creator, QByteArrayList injectables, bool weak, ServiceRegistry::DestructionScope scope) :
ServiceInfo{weak, scope},
creator{std::move(creator)},
injectables{std::move(injectables)}
{}
QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate *d) const
@ -199,9 +249,9 @@ QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate
ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject, bool weak) :
ServiceInfo(weak),
metaObject(metaObject)
ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject, bool weak, ServiceRegistry::DestructionScope scope) :
ServiceInfo{weak, scope},
metaObject{metaObject}
{}
QObject *ServiceRegistryPrivate::MetaServiceInfo::construct(ServiceRegistryPrivate *d) const

57
src/mvvmcore/serviceregistry.h

@ -17,6 +17,14 @@ class ServiceRegistryPrivate;
class Q_MVVMCORE_EXPORT ServiceRegistry
{
public:
enum DestructionScope {
DestroyOnAppQuit = 1,
DestroyOnAppDestroy = 2,
DestroyOnRegistryDestroy = 3,
DestroyNever = 127
};
//! @private
ServiceRegistry(ServiceRegistryPrivate *d_ptr);
~ServiceRegistry();
@ -32,32 +40,41 @@ public:
//! Register a service for its interface via the type
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
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
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
template <typename TService>
void registerObject(bool weak = false);
void registerObject(bool weak = false, DestructionScope scope = DestroyOnAppDestroy);
//! Register a service via a constructor function
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
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
void registerService(const QByteArray &iid,
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
void registerService(const QByteArray &iid,
const std::function<QObject*(const QObjectList &)> &fn,
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
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");
template<typename TInterface, typename TService>
void ServiceRegistry::registerInterface(bool weak)
void ServiceRegistry::registerInterface(bool weak, DestructionScope scope)
{
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>
void ServiceRegistry::registerInterface(TFunc fn, bool weak)
void ServiceRegistry::registerInterface(TFunc fn, bool weak, DestructionScope scope)
{
QTMVVM_SERVICE_ASSERT(TInterface, TService)
QByteArrayList 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>
void ServiceRegistry::registerInterface(TService *service, bool weak)
void ServiceRegistry::registerInterface(TService *service, bool weak, DestructionScope scope)
{
QTMVVM_SERVICE_ASSERT(TInterface, TService)
registerService(qobject_interface_iid<TInterface*>(), [service](const QObjectList &params) -> QObject* {
Q_UNUSED(params);
return service;
}, QByteArrayList(), weak);
}, QByteArrayList(), weak, scope);
}
#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");
template<typename TService>
void ServiceRegistry::registerObject(bool weak)
void ServiceRegistry::registerObject(bool weak, DestructionScope scope)
{
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>
void ServiceRegistry::registerObject(TFunc fn, bool weak)
void ServiceRegistry::registerObject(TFunc fn, bool weak, DestructionScope scope)
{
QTMVVM_SERVICE_ASSERT(TService)
QByteArrayList 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>
void ServiceRegistry::registerObject(TService *service, bool weak)
void ServiceRegistry::registerObject(TService *service, bool weak, DestructionScope scope)
{
QTMVVM_SERVICE_ASSERT(TService)
registerService(__helpertypes::qobject_iid<TService*>(), [service](const QObjectList &params) -> QObject* {
Q_UNUSED(params);
return service;
}, QByteArrayList(), weak);
}, QByteArrayList(), weak, scope);
}
#undef QTMVVM_SERVICE_ASSERT

13
src/mvvmcore/serviceregistry_p.h

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

Loading…
Cancel
Save