203 lines · 5.9 KB · C
RawDownload
////  DependencyManager.h//////  Created by Clément Brisset on 12/10/14.//  Copyright 2014 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #ifndef hifi_DependencyManager_h#define hifi_DependencyManager_h #include <QtGlobal>#include <QDebug>#include <QHash>#include <QtCore/QSharedPointer>#include <QWeakPointer>#include <QMutex> #include <functional>#include <typeinfo> #define SINGLETON_DEPENDENCY \    friend class ::DependencyManager; class Dependency {public:    typedef std::function<void(Dependency* pointer)> DeleterFunction; protected:    virtual ~Dependency() {}    virtual void customDeleter() {        _customDeleter(this);    }     void setCustomDeleter(DeleterFunction customDeleter) { _customDeleter = customDeleter; }    DeleterFunction _customDeleter = [](Dependency* pointer) { delete pointer; };     friend class DependencyManager;}; // usage://     auto instance = DependencyManager::get<T>();//     auto instance = DependencyManager::set<T>(Args... args);//     DependencyManager::destroy<T>();//     DependencyManager::registerInheritance<Base, Derived>();class DependencyManager {public:    template<typename T>    static QSharedPointer<T> get();     template<typename T>    static bool isSet();     template<typename T, typename ...Args>    static QSharedPointer<T> set(Args&&... args);     template<typename T, typename I, typename ...Args>    static QSharedPointer<T> set(Args&&... args);     template<typename T>    static void destroy();     template<typename Base, typename Derived>    static void registerInheritance();     template <typename T>    static size_t typeHash() {#ifdef Q_OS_ANDROID        size_t hashCode = std::hash<std::string>{}( typeid(T).name() );#else        size_t hashCode = typeid(T).hash_code();#endif        return hashCode;    }     static void prepareToExit() { manager()._exiting = true; } private:    static DependencyManager& manager();     template<typename T>    size_t getHashCode() const;     QSharedPointer<Dependency> safeGet(size_t hashCode) const;     QHash<size_t, QSharedPointer<Dependency>> _instanceHash;    QHash<size_t, size_t> _inheritanceHash;     mutable QRecursiveMutex _instanceHashMutex;    mutable QMutex _inheritanceHashMutex;     bool _exiting { false };}; template <typename T>QSharedPointer<T> DependencyManager::get() {    static size_t hashCode = manager().getHashCode<T>();    static QWeakPointer<T> instance;     if (instance.isNull()) {        instance = qSharedPointerCast<T>(manager().safeGet(hashCode)); #ifndef QT_NO_DEBUG        // debug builds...        if (instance.isNull()) {            qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name();        }#else        // for non-debug builds, don't print "No instance available" during shutdown, because        // the act of printing this often causes crashes (because the LogHandler has-been/is-being        // deleted).        if (!manager()._exiting && instance.isNull()) {            qWarning() << "DependencyManager::get(): No instance available for" << typeid(T).name();        }#endif    }     return instance.toStrongRef();} template <typename T>bool DependencyManager::isSet() {    static size_t hashCode = manager().getHashCode<T>();     QSharedPointer<Dependency> instance = manager().safeGet(hashCode);    return !instance.isNull();} template <typename T, typename ...Args>QSharedPointer<T> DependencyManager::set(Args&&... args) {    static size_t hashCode = manager().getHashCode<T>();    QMutexLocker lock(&manager()._instanceHashMutex);     // clear the previous instance before constructing the new instance    auto iter = manager()._instanceHash.find(hashCode);    if (iter != manager()._instanceHash.end()) {        iter.value().clear();    }     QSharedPointer<T> newInstance(new T(args...), &T::customDeleter);    manager()._instanceHash.insert(hashCode, newInstance);     return newInstance;} template <typename T, typename I, typename ...Args>QSharedPointer<T> DependencyManager::set(Args&&... args) {    static size_t hashCode = manager().getHashCode<T>();    QMutexLocker lock(&manager()._instanceHashMutex);     // clear the previous instance before constructing the new instance    auto iter = manager()._instanceHash.find(hashCode);    if (iter != manager()._instanceHash.end()) {        iter.value().clear();    }     QSharedPointer<T> newInstance(new I(args...), &I::customDeleter);    manager()._instanceHash.insert(hashCode, newInstance);     return newInstance;} template <typename T>void DependencyManager::destroy() {    static size_t hashCode = manager().getHashCode<T>();     QMutexLocker lock(&manager()._instanceHashMutex);    QSharedPointer<Dependency> shared = manager()._instanceHash.take(hashCode);    QWeakPointer<Dependency> weak = shared;    shared.clear();     // Check that the dependency was actually destroyed.  If it wasn't, it was improperly captured somewhere    if (weak.lock()) {        qWarning() << "DependencyManager::destroy():" << typeid(T).name() << "was not properly destroyed!";    }} template<typename Base, typename Derived>void DependencyManager::registerInheritance() {    size_t baseHashCode = typeHash<Base>();    size_t derivedHashCode = typeHash<Derived>();    QMutexLocker lock(&manager()._inheritanceHashMutex);    manager()._inheritanceHash.insert(baseHashCode, derivedHashCode);} template<typename T>size_t DependencyManager::getHashCode() const {    size_t hashCode = typeHash<T>();    QMutexLocker lock(&_inheritanceHashMutex);    auto derivedHashCode = _inheritanceHash.find(hashCode);     while (derivedHashCode != _inheritanceHash.end()) {        hashCode = derivedHashCode.value();        derivedHashCode = _inheritanceHash.find(hashCode);    }     return hashCode;} #endif // hifi_DependencyManager_h