[vlmc-devel] Rework our Singleton to provide multiple policy.
Hugo Beauzée-Luyssen
git at videolan.org
Mon Jun 27 16:40:03 CEST 2016
vlmc | branch: master | Hugo Beauzée-Luyssen <hugo at beauzee.fr> | Wed Jun 22 13:24:14 2016 +0200| [8f0edccf71ba0b5db176f5dfff52b5effd391cdc] | committer: Hugo Beauzée-Luyssen
Rework our Singleton to provide multiple policy.
This is mostly aiming at allowing Core to be destroyed within the scope
of main()
> https://code.videolan.org/videolan/vlmc/commit/8f0edccf71ba0b5db176f5dfff52b5effd391cdc
---
src/Backend/MLT/MLTBackend.h | 2 +-
src/Gui/LanguageHelper.h | 2 +-
src/Gui/widgets/NotificationZone.h | 2 +-
src/Main/Core.cpp | 7 --
src/Main/Core.h | 7 +-
src/Main/main.cpp | 2 +
src/Tools/Singleton.hpp | 149 ++++++++++++++++++++++++++++++++-----
7 files changed, 138 insertions(+), 33 deletions(-)
diff --git a/src/Backend/MLT/MLTBackend.h b/src/Backend/MLT/MLTBackend.h
index 4c2cc6d..a8022de 100644
--- a/src/Backend/MLT/MLTBackend.h
+++ b/src/Backend/MLT/MLTBackend.h
@@ -66,7 +66,7 @@ class MLTBackend : public IBackend, public Singleton<MLTBackend>
std::map<std::string, IFilterInfo*> m_availableFilters;
- friend Singleton<MLTBackend>;
+ friend Singleton_t::AllowInstantiation;
};
} // MLT
diff --git a/src/Gui/LanguageHelper.h b/src/Gui/LanguageHelper.h
index 6298c98..c646282 100644
--- a/src/Gui/LanguageHelper.h
+++ b/src/Gui/LanguageHelper.h
@@ -43,7 +43,7 @@ private:
QTranslator *m_translator;
QTranslator *m_qtTranslator;
- friend class Singleton<LanguageHelper>;
+ friend Singleton_t::AllowInstantiation;
};
#endif // LANGUAGEHELPER_H
diff --git a/src/Gui/widgets/NotificationZone.h b/src/Gui/widgets/NotificationZone.h
index 824386e..a697730 100644
--- a/src/Gui/widgets/NotificationZone.h
+++ b/src/Gui/widgets/NotificationZone.h
@@ -63,7 +63,7 @@ class NotificationZone : public QWidget, public Singleton<NotificationZone>
private slots:
void hideNotification();
- friend class Singleton<NotificationZone>;
+ friend Singleton_t::AllowInstantiation;
};
#endif // NOTIFICATIONZONE_H
diff --git a/src/Main/Core.cpp b/src/Main/Core.cpp
index 34d98f5..1dc3bcf 100644
--- a/src/Main/Core.cpp
+++ b/src/Main/Core.cpp
@@ -166,10 +166,3 @@ Core::runtime()
{
return m_timer.elapsed();
}
-
-Core*
-Core::instance()
-{
- static Core core;
- return &core;
-}
diff --git a/src/Main/Core.h b/src/Main/Core.h
index ed10319..37c3838 100644
--- a/src/Main/Core.h
+++ b/src/Main/Core.h
@@ -44,8 +44,9 @@ namespace Commands
}
#include <QElapsedTimer>
+#include "Tools/Singleton.hpp"
-class Core
+class Core : public ScopedSingleton<Core>
{
public:
Backend::IBackend* backend();
@@ -65,8 +66,6 @@ class Core
bool loadProject( const QString& fileName );
bool newProject( const QString& projectName, const QString& projectPath );
- static Core* instance();
-
private:
Core();
~Core();
@@ -85,6 +84,8 @@ class Core
Commands::AbstractUndoStack* m_undoStack;
Library* m_library;
QElapsedTimer m_timer;
+
+ friend Singleton_t::AllowInstantiation;
};
#endif // CORE_H
diff --git a/src/Main/main.cpp b/src/Main/main.cpp
index 93c3f4b..dc03f9e 100644
--- a/src/Main/main.cpp
+++ b/src/Main/main.cpp
@@ -94,6 +94,7 @@ VLMCGuimain( int argc, char **argv )
Backend::IBackend* backend;
VLMCmainCommon( app, &backend );
+ auto coreLock = Core::Policy_t::lock();
/* Load a project file */
bool project = false;
@@ -186,6 +187,7 @@ VLMCCoremain( int argc, char **argv )
Backend::IBackend* backend;
VLMCmainCommon( app, &backend );
+ auto coreLock = Core::Policy_t::lock();
/* Load a project file */
if ( app.arguments().count() < 3 )
diff --git a/src/Tools/Singleton.hpp b/src/Tools/Singleton.hpp
index 9ac7071..29266f5 100644
--- a/src/Tools/Singleton.hpp
+++ b/src/Tools/Singleton.hpp
@@ -31,40 +31,149 @@
#ifndef SINGLETON_HPP
#define SINGLETON_HPP
-#include <stdlib.h>
+#include <memory>
+#include <mutex>
+namespace details
+{
+namespace policy
+{
template <typename T>
-class Singleton
+struct OldPolicy
{
-public:
- static T* instance()
+ static T* get()
{
- if ( m_instance == nullptr )
- m_instance = new T;
- return m_instance;
+ if (s_instance == nullptr)
+ s_instance = new T;
+ return s_instance;
}
- static void destroyInstance()
+ static void release()
{
- if ( m_instance != nullptr )
+ delete s_instance;
+ s_instance = nullptr;
+ }
+
+ using InstanceType = T*;
+
+private:
+ static T* s_instance;
+};
+
+template <typename T>
+T* OldPolicy<T>::s_instance = nullptr;
+
+template <typename T>
+struct MeyersPolicy
+{
+ static T* get()
+ {
+ static T inst;
+ return &inst;
+ }
+ // No release method; automatically released when program exits
+};
+
+template <typename T>
+class ScopedPolicy
+{
+ struct Lock
+ {
+ std::shared_ptr<T> ptr;
+ friend class ScopedPolicy;
+ };
+
+public:
+ static Lock lock()
+ {
+ auto inst = s_weak_inst.lock();
+ if ( inst )
+ return Lock{ inst };
+ std::unique_lock<std::mutex> lock( s_mutex );
+ inst = s_weak_inst.lock();
+ if ( !inst )
{
- delete m_instance;
- m_instance = nullptr;
+ // use a lambda expression since the shared_ptr doesn't have access to T::~T()
+ s_weak_inst = inst = std::shared_ptr<T>( new T, [](T*ptr){ delete ptr; } );
}
+ return Lock{ inst };
+ }
+
+ static std::shared_ptr<T> get()
+ {
+ return lock().ptr;
+ }
+
+ static std::mutex s_mutex;
+ static std::weak_ptr<T> s_weak_inst;
+};
+
+template <typename T>
+std::mutex ScopedPolicy<T>::s_mutex;
+template <typename T>
+std::weak_ptr<T> ScopedPolicy<T>::s_weak_inst;
+}
+
+template <typename T, typename Policy>
+class PSingleton
+{
+public:
+ using Singleton_t = PSingleton<T, Policy>;
+ /// Meant to be used by Singleton<> users to declare the Policy as a friend class.
+ /// The AllowInstantiation just reads better than Singleton<T>::Policy_t
+ using AllowInstantiation = Policy;
+ using Policy_t = Policy;
+
+ static auto instance() -> decltype(Policy::get())
+ {
+ return Policy::get();
+ }
+
+ static void destroyInstance()
+ {
+ Policy::release();
}
-protected:
- Singleton(){}
- ~Singleton() = default;
- Singleton(const Singleton<T>&) = delete;
- Singleton(Singleton<T>&&) = delete;
- Singleton<T>& operator=(const Singleton<T>&) = delete;
- Singleton<T>& operator=(Singleton<T>&&) = delete;
protected:
- static T* m_instance;
+ PSingleton(){}
+ ~PSingleton() = default;
+
+public:
+ PSingleton(const Singleton_t&) = delete;
+ PSingleton(Singleton_t&&) = delete;
+ Singleton_t& operator=(const Singleton_t&) = delete;
+ Singleton_t& operator=(Singleton_t&&) = delete;
};
+}
+
+/**
+ * @brief Soingleton defines the "old" way of having a singleton.
+ * ie. by having to call instance()/destroyInstance() couple
+ * @warning This isn't thread safe
+ */
+template <typename T>
+using Singleton = details::PSingleton<T, details::policy::OldPolicy<T>>;
+
+/**
+ * @brief MeyersPolicy defines the usual C++11 singleton
+ * This is threadsafe, but doesn't let you control the moment the instance will be
+ * released
+ */
template <typename T>
-T* Singleton<T>::m_instance = nullptr;
+using MeyersSingleton = details::PSingleton<T, details::policy::MeyersPolicy<T>>;
+
+/**
+ * @brief Defined a singleton that will be released when the originally acquied "lock"
+ * falls out of scope
+ * Inherithing from this singleton implementation will provide a T::Policy_t::lock() method
+ * which needs to be called to acquire a lock.
+ * When this lock falls out of scope, any subsequent call to lock()/instance() will create a new instance.
+ * Calling instance() without having a lock instantiated will create a new instance that will get destroyed
+ * when the returned instance falls out of scope.
+ */
+template <typename T>
+using ScopedSingleton = details::PSingleton<T, details::policy::ScopedPolicy<T>>;
+
#endif // SINGLETON_HPP
More information about the Vlmc-devel
mailing list